提交 dac7033a 编写于 作者: M mullan

Merge

......@@ -48,132 +48,87 @@ package java.io;
* may be thrown if the input stream has been
* closed.
*
* <h4><a name="modified-utf-8">Modified UTF-8</a></h4>
* <h3><a name="modified-utf-8">Modified UTF-8</a></h3>
* <p>
* Implementations of the DataInput and DataOutput interfaces represent
* Unicode strings in a format that is a slight modification of UTF-8.
* (For information regarding the standard UTF-8 format, see section
* <i>3.9 Unicode Encoding Forms</i> of <i>The Unicode Standard, Version
* 4.0</i>).
* Note that in the following tables, the most significant bit appears in the
* Note that in the following table, the most significant bit appears in the
* far left-hand column.
* <p>
* All characters in the range {@code '\u005Cu0001'} to
* {@code '\u005Cu007F'} are represented by a single byte:
*
* <blockquote>
* <table border="1" cellspacing="0" cellpadding="8" width="50%"
* <table border="1" cellspacing="0" cellpadding="8"
* summary="Bit values and bytes">
* <tr>
* <th colspan="9"><span style="font-weight:normal">
* All characters in the range {@code '\u005Cu0001'} to
* {@code '\u005Cu007F'} are represented by a single byte:</span></th>
* </tr>
* <tr>
* <td></td>
* <th id="bit_a">Bit Values</th>
* <th colspan="8" id="bit_a">Bit Values</th>
* </tr>
* <tr>
* <th id="byte1_a">Byte 1</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>0</center>
* <td colspan="7"><center>bits 6-0</center>
* </tr>
* </table>
* </td>
* <td><center>0</center>
* <td colspan="7"><center>bits 6-0</center>
* </tr>
* <tr>
* <th colspan="9"><span style="font-weight:normal">
* The null character {@code '\u005Cu0000'} and characters
* in the range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are
* represented by a pair of bytes:</span></th>
* </tr>
* </table>
* </blockquote>
*
* <p>
* The null character {@code '\u005Cu0000'} and characters in the
* range {@code '\u005Cu0080'} to {@code '\u005Cu07FF'} are
* represented by a pair of bytes:
*
* <blockquote>
* <table border="1" cellspacing="0" cellpadding="8" width="50%"
* summary="Bit values and bytes">
* <tr>
* <td></td>
* <th id="bit_b">Bit Values</th>
* <th colspan="8" id="bit_b">Bit Values</th>
* </tr>
* <tr>
* <th id="byte1_b">Byte 1</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>1</center>
* <td width="13%"><center>1</center>
* <td width="12%"><center>0</center>
* <td colspan="5"><center>bits 10-6</center>
* </tr>
* </table>
* </td>
* <td><center>1</center>
* <td><center>1</center>
* <td><center>0</center>
* <td colspan="5"><center>bits 10-6</center>
* </tr>
* <tr>
* <th id="byte2_a">Byte 2</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>1</center>
* <td width="13%"><center>0</center>
* <td colspan="6"><center>bits 5-0</center>
* </tr>
* </table>
* </td>
* <td><center>1</center>
* <td><center>0</center>
* <td colspan="6"><center>bits 5-0</center>
* </tr>
* <tr>
* <th colspan="9"><span style="font-weight:normal">
* {@code char} values in the range {@code '\u005Cu0800'}
* to {@code '\u005CuFFFF'} are represented by three bytes:</span></th>
* </tr>
* </table>
* </blockquote>
*
* <br>
* {@code char} values in the range {@code '\u005Cu0800'} to
* {@code '\u005CuFFFF'} are represented by three bytes:
*
* <blockquote>
* <table border="1" cellspacing="0" cellpadding="8" width="50%"
* summary="Bit values and bytes">
* <tr>
* <td></td>
* <th id="bit_c">Bit Values</th>
* <th colspan="8"id="bit_c">Bit Values</th>
* </tr>
* <tr>
* <th id="byte1_c">Byte 1</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>1</center>
* <td width="13%"><center>1</center>
* <td width="12%"><center>1</center>
* <td width="13%"><center>0</center>
* <td colspan="4"><center>bits 15-12</center>
* </tr>
* </table>
* </td>
* <td><center>1</center>
* <td><center>1</center>
* <td><center>1</center>
* <td><center>0</center>
* <td colspan="4"><center>bits 15-12</center>
* </tr>
* <tr>
* <th id="byte2_b">Byte 2</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>1</center>
* <td width="13%"><center>0</center>
* <td colspan="6"><center>bits 11-6</center>
* </tr>
* </table>
* </td>
* <td><center>1</center>
* <td><center>0</center>
* <td colspan="6"><center>bits 11-6</center>
* </tr>
* <tr>
* <th id="byte3">Byte 3</th>
* <td>
* <table border="1" cellspacing="0" width="100%">
* <tr>
* <td width="12%"><center>1</center>
* <td width="13%"><center>0</center>
* <td colspan="6"><center>bits 5-0</center>
* </tr>
* </table>
* </td>
* <td><center>1</center>
* <td><center>0</center>
* <td colspan="6"><center>bits 5-0</center>
* </tr>
* </table>
* </blockquote>
*
* </blockquote>
* <p>
* The differences between this format and the
* standard UTF-8 format are the following:
......
......@@ -129,7 +129,7 @@ import sun.security.action.GetPropertyAction;
* created, the abstract pathname represented by a <code>File</code> object
* will never change.
*
* <h4>Interoperability with {@code java.nio.file} package</h4>
* <h3>Interoperability with {@code java.nio.file} package</h3>
*
* <p> The <a href="../../java/nio/file/package-summary.html">{@code java.nio.file}</a>
* package defines interfaces and classes for the Java virtual machine to access
......
/*
* Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -313,6 +313,7 @@ public class ObjectInputStream
* @throws SecurityException if a security manager exists and its
* <code>checkPermission</code> method denies enabling
* subclassing.
* @throws IOException if an I/O error occurs while creating this stream
* @see SecurityManager#checkPermission
* @see java.io.SerializablePermission
*/
......
/*
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -265,6 +265,7 @@ public class ObjectOutputStream
* @throws SecurityException if a security manager exists and its
* <code>checkPermission</code> method denies enabling
* subclassing.
* @throws IOException if an I/O error occurs while creating this stream
* @see SecurityManager#checkPermission
* @see java.io.SerializablePermission
*/
......
/*
* Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -240,6 +240,8 @@ public class ObjectStreamField
* Returns boolean value indicating whether or not the serializable field
* represented by this ObjectStreamField instance is unshared.
*
* @return {@code true} if this field is unshared
*
* @since 1.4
*/
public boolean isUnshared() {
......
......@@ -128,7 +128,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable {
* meanings are:
*
* <table summary="Access mode permitted values and meanings">
* <tr><th><p align="left">Value</p></th><th><p align="left">Meaning</p></th></tr>
* <tr><th align="left">Value</th><th align="left">Meaning</th></tr>
* <tr><td valign="top"><tt>"r"</tt></td>
* <td> Open for reading only. Invoking any of the <tt>write</tt>
* methods of the resulting object will cause an {@link
......
......@@ -157,10 +157,10 @@ public final class Class<T> implements java.io.Serializable,
*
* The string is formatted as a list of type modifiers, if any,
* followed by the kind of type (empty string for primitive types
* and {@code class}, {@code enum}, {@code interface}, or {@code
* &#64;interface}, as appropriate), followed by the type's name,
* followed by an angle-bracketed comma-separated list of the
* type's type parameters, if any.
* and {@code class}, {@code enum}, {@code interface}, or
* <code>&#64;</code>{@code interface}, as appropriate), followed
* by the type's name, followed by an angle-bracketed
* comma-separated list of the type's type parameters, if any.
*
* A space is used to separate modifiers from one another and to
* separate any modifiers from the kind of type. The modifiers
......
......@@ -29,6 +29,8 @@ package java.lang.invoke;
* LambdaConversionException
*/
public class LambdaConversionException extends Exception {
private static final long serialVersionUID = 292L + 8L;
/**
* Constructs a {@code LambdaConversionException}.
*/
......
......@@ -162,7 +162,7 @@ public final class Parameter implements AnnotatedElement {
/**
* Returns the name of the parameter. If the parameter's name is
* {@linkplain isNamePresent() present}, then this method returns
* {@linkplain #isNamePresent() present}, then this method returns
* the name provided by the class file. Otherwise, this method
* synthesizes a name of the form argN, where N is the index of
* the parameter in the descriptor of the method which declares
......
......@@ -530,7 +530,7 @@ public final class URI
* href="http://www.ietf.org/rfc/rfc2396.txt">RFC&nbsp;2396</a>,
* Appendix&nbsp;A, <b><i>except for the following deviations:</i></b> </p>
*
* <ul type=disc>
* <ul>
*
* <li><p> An empty authority component is permitted as long as it is
* followed by a non-empty path, a query component, or a fragment
......@@ -993,7 +993,7 @@ public final class URI
* <li><p> Otherwise the new URI's authority component is copied from
* this URI, and its path is computed as follows: </p>
*
* <ol type=a>
* <ol>
*
* <li><p> If the given URI's path is absolute then the new URI's path
* is taken from the given URI. </p></li>
......@@ -1241,7 +1241,7 @@ public final class URI
* <p> The host component of a URI, if defined, will have one of the
* following forms: </p>
*
* <ul type=disc>
* <ul>
*
* <li><p> A domain name consisting of one or more <i>labels</i>
* separated by period characters (<tt>'.'</tt>), optionally followed by
......@@ -1495,7 +1495,7 @@ public final class URI
*
* <p> The ordering of URIs is defined as follows: </p>
*
* <ul type=disc>
* <ul>
*
* <li><p> Two URIs with different schemes are ordered according the
* ordering of their schemes, without regard to case. </p></li>
......@@ -1513,7 +1513,7 @@ public final class URI
* <li><p> Two hierarchical URIs with identical schemes are ordered
* according to the ordering of their authority components: </p>
*
* <ul type=disc>
* <ul>
*
* <li><p> If both authority components are server-based then the URIs
* are ordered according to their user-information components; if these
......
/*
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -31,7 +31,7 @@
* <a name="channels"></a>
*
* <blockquote><table cellspacing=1 cellpadding=0 summary="Lists channels and their descriptions">
* <tr><th><p align="left">Channels</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">Channels</th><th align="left">Description</th></tr>
* <tr><td valign=top><tt><i>{@link java.nio.channels.Channel}</i></tt></td>
* <td>A nexus for I/O operations</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.channels.ReadableByteChannel}</i></tt></td>
......@@ -110,7 +110,7 @@
* write them to a given writable byte channel.
*
* <blockquote><table cellspacing=1 cellpadding=0 summary="Lists file channels and their descriptions">
* <tr><th><p align="left">File channels</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">File channels</th><th align="left">Description</th></tr>
* <tr><td valign=top><tt>{@link java.nio.channels.FileChannel}</tt></td>
* <td>Reads, writes, maps, and manipulates files</td></tr>
* <tr><td valign=top><tt>{@link java.nio.channels.FileLock}</tt></td>
......@@ -138,7 +138,7 @@
*
* <a name="multiplex"></a>
* <blockquote><table cellspacing=1 cellpadding=0 summary="Lists multiplexed, non-blocking channels and their descriptions">
* <tr><th><p align="left">Multiplexed, non-blocking I/O</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">Multiplexed, non-blocking I/O</th><th align="left"><p>Description</th></tr>
* <tr><td valign=top><tt>{@link java.nio.channels.SelectableChannel}</tt></td>
* <td>A channel that can be multiplexed</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;{@link java.nio.channels.DatagramChannel}</tt></td>
......@@ -225,7 +225,7 @@
* <a name="async"></a>
*
* <blockquote><table cellspacing=1 cellpadding=0 summary="Lists asynchronous channels and their descriptions">
* <tr><th><p align="left">Asynchronous I/O</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">Asynchronous I/O</th><th align="left">Description</th></tr>
* <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousFileChannel}</tt></td>
* <td>An asynchronous channel for reading, writing, and manipulating a file</td></tr>
* <tr><td valign=top><tt>{@link java.nio.channels.AsynchronousSocketChannel}</tt></td>
......
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -65,7 +65,7 @@ import sun.security.action.GetPropertyAction;
* concurrent threads.
*
*
* <a name="names"><a name="charenc">
* <a name="names"></a><a name="charenc"></a>
* <h2>Charset names</h2>
*
* <p> Charsets are named by strings composed of the following characters:
......@@ -111,21 +111,17 @@ import sun.security.action.GetPropertyAction;
* The aliases of a charset are returned by the {@link #aliases() aliases}
* method.
*
* <a name="hn">
*
* <p> Some charsets have an <i>historical name</i> that is defined for
* compatibility with previous versions of the Java platform. A charset's
* <p><a name="hn">Some charsets have an <i>historical name</i> that is defined for
* compatibility with previous versions of the Java platform.</a> A charset's
* historical name is either its canonical name or one of its aliases. The
* historical name is returned by the <tt>getEncoding()</tt> methods of the
* {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
* java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
*
* <a name="iana">
*
* <p> If a charset listed in the <a
* <p><a name="iana">If a charset listed in the <a
* href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
* Registry</i></a> is supported by an implementation of the Java platform then
* its canonical name must be the name listed in the registry. Many charsets
* its canonical name must be the name listed in the registry.</a> Many charsets
* are given more than one name in the registry, in which case the registry
* identifies one of the names as <i>MIME-preferred</i>. If a charset has more
* than one registry name then its canonical name must be the MIME-preferred
......@@ -142,15 +138,15 @@ import sun.security.action.GetPropertyAction;
*
* <h2>Standard charsets</h2>
*
* <a name="standard">
*
* <p> Every implementation of the Java platform is required to support the
* following standard charsets. Consult the release documentation for your
*
* <p><a name="standard">Every implementation of the Java platform is required to support the
* following standard charsets.</a> Consult the release documentation for your
* implementation to see if any other charsets are supported. The behavior
* of such optional charsets may differ between implementations.
*
* <blockquote><table width="80%" summary="Description of standard charsets">
* <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">Charset</th><th align="left">Description</th></tr>
* <tr><td valign=top><tt>US-ASCII</tt></td>
* <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
* a.k.a. the Basic Latin block of the Unicode character set</td></tr>
......
/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -42,14 +42,27 @@ public class MalformedInputException
private int inputLength;
/**
* Constructs an {@code MalformedInputException} with the given
* length.
* @param inputLength the length of the input
*/
public MalformedInputException(int inputLength) {
this.inputLength = inputLength;
}
/**
* Returns the length of the input.
* @return the length of the input
*/
public int getInputLength() {
return inputLength;
}
/**
* Returns the message.
* @return the message
*/
public String getMessage() {
return "Input length = " + inputLength;
}
......
/*
* Copyright (c) 2001, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -42,14 +42,27 @@ public class UnmappableCharacterException
private int inputLength;
/**
* Constructs an {@code UnmappableCharacterException} with the
* given length.
* @param inputLength the length of the input
*/
public UnmappableCharacterException(int inputLength) {
this.inputLength = inputLength;
}
/**
* Returns the length of the input.
* @return the length of the input
*/
public int getInputLength() {
return inputLength;
}
/**
* Returns the message.
* @return the message
*/
public String getMessage() {
return "Input length = " + inputLength;
}
......
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -27,7 +27,7 @@
* Interfaces and classes providing access to file and file system attributes.
*
* <blockquote><table cellspacing=1 cellpadding=0 summary="Attribute views">
* <tr><th><p align="left">Attribute views</p></th><th><p align="left">Description</p></th></tr>
* <tr><th align="left">Attribute views</th><th align="left">Description</th></tr>
* <tr><td valign=top><tt><i>{@link java.nio.file.attribute.AttributeView}</i></tt></td>
* <td>Can read or update non-opaque values associated with objects in a file system</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;<i>{@link java.nio.file.attribute.FileAttributeView}</i></tt></td>
......@@ -38,7 +38,7 @@
* <td>Can read or update POSIX defined file attributes</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.DosFileAttributeView}&nbsp;&nbsp;</i></tt></td>
* <td>Can read or update FAT file attributes</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp<i>{@link java.nio.file.attribute.FileOwnerAttributeView}&nbsp;&nbsp;</i></tt></td>
* <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.FileOwnerAttributeView}&nbsp;&nbsp;</i></tt></td>
* <td>Can read or update the owner of a file</td></tr>
* <tr><td valign=top><tt>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<i>{@link java.nio.file.attribute.AclFileAttributeView}&nbsp;&nbsp;</i></tt></td>
* <td>Can read or update Access Control Lists</td></tr>
......@@ -86,14 +86,14 @@
*
* <ul>
*
* <p><li> The {@link java.nio.file.attribute.UserPrincipal} and
* <li> The {@link java.nio.file.attribute.UserPrincipal} and
* {@link java.nio.file.attribute.GroupPrincipal} interfaces represent an
* identity or group identity. </li>
*
* <p><li> The {@link java.nio.file.attribute.UserPrincipalLookupService}
* <li> The {@link java.nio.file.attribute.UserPrincipalLookupService}
* interface defines methods to lookup user or group principals. </li>
*
* <p><li> The {@link java.nio.file.attribute.FileAttribute} interface
* <li> The {@link java.nio.file.attribute.FileAttribute} interface
* represents the value of an attribute for cases where the attribute value is
* required to be set atomically when creating an object in the file system. </li>
*
......
/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -33,8 +33,8 @@
* package is used by service provider implementors wishing to extend the
* platform default provider, or to construct other provider implementations. </p>
*
* <a name="links"><h3>Symbolic Links</h3></a>
* Many operating systems and file systems support for <em>symbolic links</em>.
* <h3><a name="links">Symbolic Links</a></h3>
* <p> Many operating systems and file systems support for <em>symbolic links</em>.
* A symbolic link is a special file that serves as a reference to another file.
* For the most part, symbolic links are transparent to applications and
* operations on symbolic links are automatically redirected to the <em>target</em>
......@@ -45,8 +45,8 @@
* that are semantically close but support for these other types of links is
* not included in this package. </p>
*
* <a name="interop"><h3>Interoperability</h3></a>
* The {@link java.io.File} class defines the {@link java.io.File#toPath
* <h3><a name="interop">Interoperability</a></h3>
* <p> The {@link java.io.File} class defines the {@link java.io.File#toPath
* toPath} method to construct a {@link java.nio.file.Path} by converting
* the abstract path represented by the {@code java.io.File} object. The resulting
* {@code Path} can be used to operate on the same file as the {@code File}
......@@ -55,7 +55,7 @@
* and {@code java.io.File} objects. </p>
*
* <h3>Visibility</h3>
* The view of the files and file system provided by classes in this package are
* <p> The view of the files and file system provided by classes in this package are
* guaranteed to be consistent with other views provided by other instances in the
* same Java virtual machine. The view may or may not, however, be consistent with
* the view of the file system as seen by other concurrently running programs due
......@@ -65,8 +65,8 @@
* or on some other machine. The exact nature of any such inconsistencies are
* system-dependent and are therefore unspecified. </p>
*
* <a name="integrity"><h3>Synchronized I/O File Integrity</h3></a>
* The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link
* <h3><a name="integrity">Synchronized I/O File Integrity</a></h3>
* <p> The {@link java.nio.file.StandardOpenOption#SYNC SYNC} and {@link
* java.nio.file.StandardOpenOption#DSYNC DSYNC} options are used when opening a file
* to require that updates to the file are written synchronously to the underlying
* storage device. In the case of the default provider, and the file resides on
......@@ -83,7 +83,7 @@
* specific. </p>
*
* <h3>General Exceptions</h3>
* Unless otherwise noted, passing a {@code null} argument to a constructor
* <p> Unless otherwise noted, passing a {@code null} argument to a constructor
* or method of any class or interface in this package will cause a {@link
* java.lang.NullPointerException NullPointerException} to be thrown. Additionally,
* invoking a method with a collection containing a {@code null} element will
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -50,21 +50,26 @@ import java.util.Set;
* status of certificates with OCSP and CRLs. By default, OCSP is the
* preferred mechanism for checking revocation status, with CRLs as the
* fallback mechanism. However, this preference can be switched to CRLs with
* the {@link Option#PREFER_CRLS PREFER_CRLS} option.
* the {@link Option#PREFER_CRLS PREFER_CRLS} option. In addition, the fallback
* mechanism can be disabled with the {@link Option#NO_FALLBACK NO_FALLBACK}
* option.
*
* <p>A {@code PKIXRevocationChecker} is obtained by calling the
* {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
* of a PKIX {@code CertPathValidator}. Additional parameters and options
* specific to revocation can be set (by calling {@link #setOCSPResponder}
* method for instance). The {@code PKIXRevocationChecker} is added to
* a {@code PKIXParameters} object using the
* {@link PKIXParameters#addCertPathChecker addCertPathChecker}
* specific to revocation can be set (by calling the
* {@link #setOcspResponder setOcspResponder} method for instance). The
* {@code PKIXRevocationChecker} is added to a {@code PKIXParameters} object
* using the {@link PKIXParameters#addCertPathChecker addCertPathChecker}
* or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
* and then the {@code PKIXParameters} is passed along with the {@code CertPath}
* to be validated to the {@link CertPathValidator#validate validate} method
* of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
* this manner, it will be used to check revocation irrespective of the setting
* of the {@link PKIXParameters#isRevocationEnabled RevocationEnabled} flag.
* Similarly, a {@code PKIXRevocationChecker} may be added to a
* {@code PKIXBuilderParameters} object for use with a PKIX
* {@code CertPathBuilder}.
*
* <p>Note that when a {@code PKIXRevocationChecker} is added to
* {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
......@@ -83,6 +88,13 @@ import java.util.Set;
* need not synchronize.
*
* @since 1.8
*
* @see <a href="http://www.ietf.org/rfc/rfc2560.txt"><i>RFC&nbsp;2560: X.509
* Internet Public Key Infrastructure Online Certificate Status Protocol -
* OCSP</i></a>, <br><a
* href="http://www.ietf.org/rfc/rfc5280.txt"><i>RFC&nbsp;5280: Internet X.509
* Public Key Infrastructure Certificate and Certificate Revocation List (CRL)
* Profile</i></a>
*/
public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
private URI ocspResponder;
......@@ -101,7 +113,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @param uri the responder URI
*/
public void setOCSPResponder(URI uri) {
public void setOcspResponder(URI uri) {
this.ocspResponder = uri;
}
......@@ -114,7 +126,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @return the responder URI, or {@code null} if not set
*/
public URI getOCSPResponder() {
public URI getOcspResponder() {
return ocspResponder;
}
......@@ -126,7 +138,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @param cert the responder's certificate
*/
public void setOCSPResponderCert(X509Certificate cert) {
public void setOcspResponderCert(X509Certificate cert) {
this.ocspResponderCert = cert;
}
......@@ -140,7 +152,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*
* @return the responder's certificate, or {@code null} if not set
*/
public X509Certificate getOCSPResponderCert() {
public X509Certificate getOcspResponderCert() {
return ocspResponderCert;
}
......@@ -151,7 +163,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
* @param extensions a list of extensions. The list is copied to protect
* against subsequent modification.
*/
public void setOCSPExtensions(List<Extension> extensions)
public void setOcspExtensions(List<Extension> extensions)
{
this.ocspExtensions = (extensions == null)
? Collections.<Extension>emptyList()
......@@ -161,10 +173,10 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
/**
* Gets the optional OCSP request extensions.
*
* @return an unmodifiable list of extensions. Returns an empty list if no
* @return an unmodifiable list of extensions. The list is empty if no
* extensions have been specified.
*/
public List<Extension> getOCSPExtensions() {
public List<Extension> getOcspExtensions() {
return Collections.unmodifiableList(ocspExtensions);
}
......@@ -177,7 +189,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
* DER-encoded OCSP response for that certificate. A deep copy of
* the map is performed to protect against subsequent modification.
*/
public void setOCSPResponses(Map<X509Certificate, byte[]> responses)
public void setOcspResponses(Map<X509Certificate, byte[]> responses)
{
if (responses == null) {
this.ocspResponses = Collections.<X509Certificate, byte[]>emptyMap();
......@@ -200,7 +212,7 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
* the map is returned to protect against subsequent modification.
* Returns an empty map if no responses have been specified.
*/
public Map<X509Certificate, byte[]> getOCSPResponses() {
public Map<X509Certificate, byte[]> getOcspResponses() {
Map<X509Certificate, byte[]> copy = new HashMap<>(ocspResponses.size());
for (Map.Entry<X509Certificate, byte[]> e : ocspResponses.entrySet()) {
copy.put(e.getKey(), e.getValue().clone());
......@@ -223,15 +235,31 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
/**
* Gets the revocation options.
*
* @return an unmodifiable set of revocation options, or an empty set if
* none are specified
* @return an unmodifiable set of revocation options. The set is empty if
* no options have been specified.
*/
public Set<Option> getOptions() {
return Collections.unmodifiableSet(options);
}
/**
* Returns a list containing the exceptions that are ignored by the
* revocation checker when the {@link Option#SOFT_FAIL SOFT_FAIL} option
* is set. The list is cleared each time {@link #init init} is called.
* The list is ordered in ascending order according to the certificate
* index returned by {@link CertPathValidatorException#getIndex getIndex}
* method of each entry.
* <p>
* An implementation of {@code PKIXRevocationChecker} is responsible for
* adding the ignored exceptions to the list.
*
* @return an unmodifiable list containing the ignored exceptions. The list
* is empty if no exceptions have been ignored.
*/
public abstract List<CertPathValidatorException> getSoftFailExceptions();
@Override
public Object clone() {
public PKIXRevocationChecker clone() {
PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
copy.ocspExtensions = new ArrayList<>(ocspExtensions);
copy.ocspResponses = new HashMap<>(ocspResponses);
......@@ -262,9 +290,26 @@ public abstract class PKIXRevocationChecker extends PKIXCertPathChecker {
*/
PREFER_CRLS,
/**
* Ignore network failures. The default behavior is to consider it a
* failure if the revocation status of a certificate cannot be obtained
* due to a network error. This option applies to both OCSP and CRLs.
* Disable the fallback mechanism.
*/
NO_FALLBACK,
/**
* Allow revocation check to succeed if the revocation status cannot be
* determined for one of the following reasons:
* <p><ul>
* <li>The CRL or OCSP response cannot be obtained because of a
* network error.
* <li>The OCSP responder returns one of the following errors
* specified in section 2.3 of RFC 2560: internalError, tryLater,
* or unauthorized.
* </ul><br>
* Note that these conditions apply to both OCSP and CRLs, and unless
* the {@code NO_FALLBACK} option is set, the revocation check is
* allowed to succeed only if both mechanisms fail under one of the
* conditions as stated above.
* Exceptions that cause the network errors are ignored but can be
* later retrieved by calling the
* {@link #getSoftFailExceptions getSoftFailExceptions} method.
*/
SOFT_FAIL
}
......
......@@ -61,7 +61,6 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoUnit.DAYS;
......@@ -73,6 +72,7 @@ import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.time.temporal.WeekFields;
import java.util.Locale;
......@@ -339,7 +339,7 @@ public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
if (field == DAY_OF_WEEK) {
return getValue();
} else if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......
......@@ -459,9 +459,9 @@ public final class Duration
*/
public static Duration between(Temporal startInclusive, Temporal endExclusive) {
try {
return ofNanos(startInclusive.periodUntil(endExclusive, NANOS));
return ofNanos(startInclusive.until(endExclusive, NANOS));
} catch (DateTimeException | ArithmeticException ex) {
long secs = startInclusive.periodUntil(endExclusive, SECONDS);
long secs = startInclusive.until(endExclusive, SECONDS);
long nanos;
try {
nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND);
......@@ -523,7 +523,7 @@ public final class Duration
} else if (unit == NANOS) {
return nanos;
} else {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
}
......
......@@ -69,6 +69,7 @@ import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.MICRO_OF_SECOND;
import static java.time.temporal.ChronoField.MILLI_OF_SECOND;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.NANOS;
import java.io.DataInput;
......@@ -418,8 +419,9 @@ public final class Instant
* Checks if the specified field is supported.
* <p>
* This checks if this instant can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -447,6 +449,44 @@ public final class Instant
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* <li>{@code DAYS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit.isTimeBased() || unit == DAYS;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -511,7 +551,7 @@ public final class Instant
case MILLI_OF_SECOND: return nanos / 1000_000;
case INSTANT_SECONDS: INSTANT_SECONDS.checkValidIntValue(seconds);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return range(field).checkValidIntValue(field.getFrom(this), field);
}
......@@ -548,7 +588,7 @@ public final class Instant
case MILLI_OF_SECOND: return nanos / 1000_000;
case INSTANT_SECONDS: return seconds;
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......@@ -665,7 +705,7 @@ public final class Instant
case NANO_OF_SECOND: return (newValue != nanos ? create(seconds, (int) newValue) : this);
case INSTANT_SECONDS: return (newValue != seconds ? create(newValue, nanos) : this);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
......@@ -807,7 +847,7 @@ public final class Instant
case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
......@@ -1053,14 +1093,14 @@ public final class Instant
* complete units between the two instants.
* The {@code Temporal} passed to this method must be an {@code Instant}.
* For example, the amount in days between two dates can be calculated
* using {@code startInstant.periodUntil(endInstant, SECONDS)}.
* using {@code startInstant.until(endInstant, SECONDS)}.
* <p>
* There are two equivalent ways of using this method.
* The first is to invoke this method.
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, SECONDS);
* amount = start.until(end, SECONDS);
* amount = SECONDS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1085,7 +1125,7 @@ public final class Instant
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endInstant, TemporalUnit unit) {
public long until(Temporal endInstant, TemporalUnit unit) {
if (endInstant instanceof Instant == false) {
Objects.requireNonNull(endInstant, "endInstant");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -1103,7 +1143,7 @@ public final class Instant
case HALF_DAYS: return secondsUntil(end) / (12 * SECONDS_PER_HOUR);
case DAYS: return secondsUntil(end) / (SECONDS_PER_DAY);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endInstant);
}
......
......@@ -127,7 +127,7 @@ import java.util.Objects;
* @since 1.8
*/
public final class LocalDate
implements Temporal, TemporalAdjuster, ChronoLocalDate<LocalDate>, Serializable {
implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable {
/**
* The minimum supported {@code LocalDate}, '-999999999-01-01'.
......@@ -466,8 +466,9 @@ public final class LocalDate
* Checks if the specified field is supported.
* <p>
* This checks if this date can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -501,6 +502,41 @@ public final class LocalDate
return ChronoLocalDate.super.isSupported(field);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code DAYS}
* <li>{@code WEEKS}
* <li>{@code MONTHS}
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
return ChronoLocalDate.super.isSupported(unit);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -538,7 +574,7 @@ public final class LocalDate
}
return field.range();
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.rangeRefinedBy(this);
}
......@@ -631,7 +667,7 @@ public final class LocalDate
case YEAR: return year;
case ERA: return (year >= 1 ? 1 : 0);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
private long getProlepticMonth() {
......@@ -988,7 +1024,7 @@ public final class LocalDate
case YEAR: return withYear((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
......@@ -1187,7 +1223,7 @@ public final class LocalDate
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
......@@ -1497,7 +1533,7 @@ public final class LocalDate
* The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalDate}.
* For example, the amount in days between two dates can be calculated
* using {@code startDate.periodUntil(endDate, DAYS)}.
* using {@code startDate.until(endDate, DAYS)}.
* <p>
* The calculation returns a whole number, representing the number of
* complete units between the two dates.
......@@ -1509,7 +1545,7 @@ public final class LocalDate
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1534,7 +1570,7 @@ public final class LocalDate
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endDate, TemporalUnit unit) {
public long until(Temporal endDate, TemporalUnit unit) {
Objects.requireNonNull(unit, "unit");
if (endDate instanceof LocalDate == false) {
Objects.requireNonNull(endDate, "endDate");
......@@ -1552,7 +1588,7 @@ public final class LocalDate
case MILLENNIA: return monthsUntil(end) / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endDate);
}
......@@ -1591,7 +1627,7 @@ public final class LocalDate
* The second is to use {@link Period#between(LocalDate, LocalDate)}:
* <pre>
* // these two lines are equivalent
* period = start.periodUntil(end);
* period = start.until(end);
* period = Period.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1600,7 +1636,7 @@ public final class LocalDate
* @return the period between this date and the end date, not null
*/
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
public Period until(ChronoLocalDate endDate) {
LocalDate end = LocalDate.from(endDate);
long totalMonths = end.getProlepticMonth() - this.getProlepticMonth(); // safe
int days = end.day - this.day;
......@@ -1803,7 +1839,7 @@ public final class LocalDate
* @return the comparator value, negative if less, positive if greater
*/
@Override // override for Javadoc and performance
public int compareTo(ChronoLocalDate<?> other) {
public int compareTo(ChronoLocalDate other) {
if (other instanceof LocalDate) {
return compareTo0((LocalDate) other);
}
......@@ -1843,7 +1879,7 @@ public final class LocalDate
* @return true if this date is after the specified date
*/
@Override // override for Javadoc and performance
public boolean isAfter(ChronoLocalDate<?> other) {
public boolean isAfter(ChronoLocalDate other) {
if (other instanceof LocalDate) {
return compareTo0((LocalDate) other) > 0;
}
......@@ -1872,7 +1908,7 @@ public final class LocalDate
* @return true if this date is before the specified date
*/
@Override // override for Javadoc and performance
public boolean isBefore(ChronoLocalDate<?> other) {
public boolean isBefore(ChronoLocalDate other) {
if (other instanceof LocalDate) {
return compareTo0((LocalDate) other) < 0;
}
......@@ -1901,7 +1937,7 @@ public final class LocalDate
* @return true if this date is equal to the specified date
*/
@Override // override for Javadoc and performance
public boolean isEqual(ChronoLocalDate<?> other) {
public boolean isEqual(ChronoLocalDate other) {
if (other instanceof LocalDate) {
return compareTo0((LocalDate) other) == 0;
}
......
......@@ -515,8 +515,9 @@ public final class LocalDateTime
* Checks if the specified field is supported.
* <p>
* This checks if this date-time can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -569,6 +570,48 @@ public final class LocalDateTime
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* <li>{@code DAYS}
* <li>{@code WEEKS}
* <li>{@code MONTHS}
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
return ChronoLocalDateTime.super.isSupported(unit);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -1570,7 +1613,7 @@ public final class LocalDateTime
* The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalDateTime}.
* For example, the amount in days between two date-times can be calculated
* using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
* using {@code startDateTime.until(endDateTime, DAYS)}.
* <p>
* The calculation returns a whole number, representing the number of
* complete units between the two date-times.
......@@ -1582,7 +1625,7 @@ public final class LocalDateTime
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1609,18 +1652,17 @@ public final class LocalDateTime
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof LocalDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
}
LocalDateTime end = (LocalDateTime) endDateTime;
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
if (f.isTimeUnit()) {
if (unit.isTimeBased()) {
long amount = date.daysUntil(end.date);
if (amount == 0) {
return time.periodUntil(end.time, unit);
return time.until(end.time, unit);
}
long timePart = end.time.toNanoOfDay() - time.toNanoOfDay();
if (amount > 0) {
......@@ -1630,7 +1672,7 @@ public final class LocalDateTime
amount++; // safe
timePart -= NANOS_PER_DAY; // safe
}
switch (f) {
switch ((ChronoUnit) unit) {
case NANOS:
amount = Math.multiplyExact(amount, NANOS_PER_DAY);
break;
......@@ -1667,7 +1709,7 @@ public final class LocalDateTime
} else if (endDate.isBefore(date) && end.time.isAfter(time)) {
endDate = endDate.plusDays(1);
}
return date.periodUntil(endDate, unit);
return date.until(endDate, unit);
}
return unit.between(this, endDateTime);
}
......
......@@ -470,8 +470,9 @@ public final class LocalTime
* Checks if the specified field is supported.
* <p>
* This checks if this time can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -510,6 +511,43 @@ public final class LocalTime
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit.isTimeBased();
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -628,7 +666,7 @@ public final class LocalTime
case CLOCK_HOUR_OF_DAY: return (hour == 0 ? 24 : hour);
case AMPM_OF_DAY: return hour / 12;
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
//-----------------------------------------------------------------------
......@@ -803,7 +841,7 @@ public final class LocalTime
case CLOCK_HOUR_OF_DAY: return withHour((int) (newValue == 24 ? 0 : newValue));
case AMPM_OF_DAY: return plusHours((newValue - (hour / 12)) * 12);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
......@@ -995,8 +1033,7 @@ public final class LocalTime
@Override
public LocalTime plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
switch (f) {
switch ((ChronoUnit) unit) {
case NANOS: return plusNanos(amountToAdd);
case MICROS: return plusNanos((amountToAdd % MICROS_PER_DAY) * 1000);
case MILLIS: return plusNanos((amountToAdd % MILLIS_PER_DAY) * 1000_000);
......@@ -1005,7 +1042,7 @@ public final class LocalTime
case HOURS: return plusHours(amountToAdd);
case HALF_DAYS: return plusHours((amountToAdd % 2) * 12);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
......@@ -1295,7 +1332,7 @@ public final class LocalTime
* The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code LocalTime}.
* For example, the amount in hours between two times can be calculated
* using {@code startTime.periodUntil(endTime, HOURS)}.
* using {@code startTime.until(endTime, HOURS)}.
* <p>
* The calculation returns a whole number, representing the number of
* complete units between the two times.
......@@ -1307,7 +1344,7 @@ public final class LocalTime
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MINUTES);
* amount = start.until(end, MINUTES);
* amount = MINUTES.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1332,7 +1369,7 @@ public final class LocalTime
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endTime, TemporalUnit unit) {
public long until(Temporal endTime, TemporalUnit unit) {
if (endTime instanceof LocalTime == false) {
Objects.requireNonNull(endTime, "endTime");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -1349,7 +1386,7 @@ public final class LocalTime
case HOURS: return nanosUntil / NANOS_PER_HOUR;
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endTime);
}
......
......@@ -61,7 +61,6 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoUnit.MONTHS;
......@@ -75,6 +74,7 @@ import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Locale;
......@@ -370,7 +370,7 @@ public enum Month implements TemporalAccessor, TemporalAdjuster {
if (field == MONTH_OF_YEAR) {
return getValue();
} else if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......
......@@ -438,7 +438,7 @@ public final class MonthDay
case DAY_OF_MONTH: return day;
case MONTH_OF_YEAR: return month;
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......
......@@ -65,6 +65,7 @@ import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.NANO_OF_DAY;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoUnit.FOREVER;
import static java.time.temporal.ChronoUnit.NANOS;
import java.io.IOException;
......@@ -137,25 +138,40 @@ public final class OffsetDateTime
public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN);
/**
* Comparator for two {@code OffsetDateTime} instances based solely on the instant.
* Gets a comparator that compares two {@code OffsetDateTime} instances
* based solely on the instant.
* <p>
* This method differs from the comparison in {@link #compareTo} in that it
* only compares the underlying instant.
*
* @return a comparator that compares in time-line order
*
* @see #isAfter
* @see #isBefore
* @see #isEqual
*/
public static final Comparator<OffsetDateTime> INSTANT_COMPARATOR = new Comparator<OffsetDateTime>() {
@Override
public int compare(OffsetDateTime datetime1, OffsetDateTime datetime2) {
int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
if (cmp == 0) {
cmp = Long.compare(datetime1.toLocalTime().toNanoOfDay(), datetime2.toLocalTime().toNanoOfDay());
}
return cmp;
public static Comparator<OffsetDateTime> timeLineOrder() {
return OffsetDateTime::compareInstant;
}
/**
* Compares this {@code OffsetDateTime} to another date-time.
* The comparison is based on the instant.
*
* @param datetime1 the first date-time to compare, not null
* @param datetime2 the other date-time to compare to, not null
* @return the comparator value, negative if less, positive if greater
*/
private static int compareInstant(OffsetDateTime datetime1, OffsetDateTime datetime2) {
if (datetime1.getOffset().equals(datetime2.getOffset())) {
return datetime1.toLocalDateTime().compareTo(datetime2.toLocalDateTime());
}
int cmp = Long.compare(datetime1.toEpochSecond(), datetime2.toEpochSecond());
if (cmp == 0) {
cmp = datetime1.toLocalTime().getNano() - datetime2.toLocalTime().getNano();
}
};
return cmp;
}
/**
* Serialization version.
......@@ -406,8 +422,9 @@ public final class OffsetDateTime
* Checks if the specified field is supported.
* <p>
* This checks if this date-time can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -458,6 +475,51 @@ public final class OffsetDateTime
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* <li>{@code DAYS}
* <li>{@code WEEKS}
* <li>{@code MONTHS}
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit != FOREVER;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -1528,7 +1590,7 @@ public final class OffsetDateTime
* The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start.
* For example, the period in days between two date-times can be calculated
* using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
* using {@code startDateTime.until(endDateTime, DAYS)}.
* <p>
* The {@code Temporal} passed to this method must be an {@code OffsetDateTime}.
* If the offset differs between the two date-times, the specified
......@@ -1544,7 +1606,7 @@ public final class OffsetDateTime
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1571,7 +1633,7 @@ public final class OffsetDateTime
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof OffsetDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -1579,7 +1641,7 @@ public final class OffsetDateTime
if (unit instanceof ChronoUnit) {
OffsetDateTime end = (OffsetDateTime) endDateTime;
end = end.withOffsetSameInstant(offset);
return dateTime.periodUntil(end.dateTime, unit);
return dateTime.until(end.dateTime, unit);
}
return unit.between(this, endDateTime);
}
......@@ -1724,15 +1786,9 @@ public final class OffsetDateTime
*/
@Override
public int compareTo(OffsetDateTime other) {
if (getOffset().equals(other.getOffset())) {
return toLocalDateTime().compareTo(other.toLocalDateTime());
}
int cmp = Long.compare(toEpochSecond(), other.toEpochSecond());
int cmp = compareInstant(this, other);
if (cmp == 0) {
cmp = toLocalTime().getNano() - other.toLocalTime().getNano();
if (cmp == 0) {
cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
}
cmp = toLocalDateTime().compareTo(other.toLocalDateTime());
}
return cmp;
}
......
......@@ -348,8 +348,9 @@ public final class OffsetTime
* Checks if the specified field is supported.
* <p>
* This checks if this time can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -389,6 +390,43 @@ public final class OffsetTime
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit.isTimeBased();
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -1084,7 +1122,7 @@ public final class OffsetTime
* The start and end points are {@code this} and the specified time.
* The result will be negative if the end is before the start.
* For example, the period in hours between two times can be calculated
* using {@code startTime.periodUntil(endTime, HOURS)}.
* using {@code startTime.until(endTime, HOURS)}.
* <p>
* The {@code Temporal} passed to this method must be an {@code OffsetTime}.
* If the offset differs between the two times, then the specified
......@@ -1100,7 +1138,7 @@ public final class OffsetTime
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MINUTES);
* amount = start.until(end, MINUTES);
* amount = MINUTES.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -1125,7 +1163,7 @@ public final class OffsetTime
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endTime, TemporalUnit unit) {
public long until(Temporal endTime, TemporalUnit unit) {
if (endTime instanceof OffsetTime == false) {
Objects.requireNonNull(endTime, "endTime");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -1142,7 +1180,7 @@ public final class OffsetTime
case HOURS: return nanosUntil / NANOS_PER_HOUR;
case HALF_DAYS: return nanosUntil / (12 * NANOS_PER_HOUR);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endTime);
}
......
......@@ -139,7 +139,7 @@ public final class Period
* The pattern for parsing.
*/
private final static Pattern PATTERN =
Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
Pattern.compile("([-+]?)P(?:([-+]?[0-9]+)Y)?(?:([-+]?[0-9]+)M)?(?:([-+]?[0-9]+)W)?(?:([-+]?[0-9]+)D)?", Pattern.CASE_INSENSITIVE);
/**
* The set of supported units.
*/
......@@ -186,6 +186,20 @@ public final class Period
return create(0, months, 0);
}
/**
* Obtains a {@code Period} representing a number of weeks.
* <p>
* The resulting period will be day-based, with the amount of days
* equal to the number of weeks multiplied by 7.
* The years and months units will be zero.
*
* @param weeks the number of weeks, positive or negative
* @return the period, with the input weeks converted to days, not null
*/
public static Period ofWeeks(int weeks) {
return create(0, 0, Math.multiplyExact(weeks, 7));
}
/**
* Obtains a {@code Period} representing a number of days.
* <p>
......@@ -257,22 +271,36 @@ public final class Period
* Obtains a {@code Period} from a text string such as {@code PnYnMnD}.
* <p>
* This will parse the string produced by {@code toString()} which is
* based on the ISO-8601 period format {@code PnYnMnD}.
* based on the ISO-8601 period formats {@code PnYnMnD} and {@code PnW}.
* <p>
* The string starts with an optional sign, denoted by the ASCII negative
* or positive symbol. If negative, the whole period is negated.
* The ASCII letter "P" is next in upper or lower case.
* There are then three sections, each consisting of a number and a suffix.
* At least one of the three sections must be present.
* The sections have suffixes in ASCII of "Y", "M" and "D" for
* years, months and days, accepted in upper or lower case.
* There are then four sections, each consisting of a number and a suffix.
* At least one of the four sections must be present.
* The sections have suffixes in ASCII of "Y", "M", "W" and "D" for
* years, months, weeks and days, accepted in upper or lower case.
* The suffixes must occur in order.
* The number part of each section must consist of ASCII digits.
* The number may be prefixed by the ASCII negative or positive symbol.
* The number must parse to an {@code int}.
* <p>
* The leading plus/minus sign, and negative values for other units are
* not part of the ISO-8601 standard.
* not part of the ISO-8601 standard. In addition, ISO-8601 does not
* permit mixing between the {@code PnYnMnD} and {@code PnW} formats.
* Any week-based input is multiplied by 7 and treated as a number of days.
* <p>
* For example, the following are valid inputs:
* <pre>
* "P2Y" -- Period.ofYears(2)
* "P3M" -- Period.ofMonths(3)
* "P4W" -- Period.ofWeeks(4)
* "P5D" -- Period.ofDays(5)
* "P1Y2M3D" -- Period.of(1, 2, 3)
* "P1Y2M3W4D" -- Period.of(1, 2, 25)
* "P-1Y2M" -- Period.of(-1, 2, 0)
* "-P1Y2M" -- Period.of(-1, -2, 0)
* </pre>
*
* @param text the text to parse, not null
* @return the parsed period, not null
......@@ -285,14 +313,18 @@ public final class Period
int negate = ("-".equals(matcher.group(1)) ? -1 : 1);
String yearMatch = matcher.group(2);
String monthMatch = matcher.group(3);
String dayMatch = matcher.group(4);
if (yearMatch != null || monthMatch != null || dayMatch != null) {
String weekMatch = matcher.group(4);
String dayMatch = matcher.group(5);
if (yearMatch != null || monthMatch != null || dayMatch != null || weekMatch != null) {
try {
return create(parseNumber(text, yearMatch, negate),
parseNumber(text, monthMatch, negate),
parseNumber(text, dayMatch, negate));
int years = parseNumber(text, yearMatch, negate);
int months = parseNumber(text, monthMatch, negate);
int weeks = parseNumber(text, weekMatch, negate);
int days = parseNumber(text, dayMatch, negate);
days = Math.addExact(days, Math.multiplyExact(weeks, 7));
return create(years, months, days);
} catch (NumberFormatException ex) {
throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex);
throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
}
}
}
......@@ -307,7 +339,7 @@ public final class Period
try {
return Math.multiplyExact(val, negate);
} catch (ArithmeticException ex) {
throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Period", text, 0).initCause(ex);
throw new DateTimeParseException("Text cannot be parsed to a Period", text, 0, ex);
}
}
......@@ -329,10 +361,10 @@ public final class Period
* @param startDate the start date, inclusive, not null
* @param endDate the end date, exclusive, not null
* @return the period between this date and the end date, not null
* @see ChronoLocalDate#periodUntil(ChronoLocalDate)
* @see ChronoLocalDate#until(ChronoLocalDate)
*/
public static Period between(LocalDate startDate, LocalDate endDate) {
return startDate.periodUntil(endDate);
return startDate.until(endDate);
}
//-----------------------------------------------------------------------
......@@ -386,7 +418,7 @@ public final class Period
} else if (unit == ChronoUnit.DAYS) {
return getDays();
} else {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
}
......
......@@ -64,6 +64,10 @@ package java.time;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import static java.time.temporal.ChronoUnit.CENTURIES;
import static java.time.temporal.ChronoUnit.DECADES;
import static java.time.temporal.ChronoUnit.ERAS;
import static java.time.temporal.ChronoUnit.MILLENNIA;
import static java.time.temporal.ChronoUnit.YEARS;
import java.io.DataInput;
......@@ -329,8 +333,9 @@ public final class Year
* Checks if the specified field is supported.
* <p>
* This checks if this year can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -357,6 +362,41 @@ public final class Year
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -450,7 +490,7 @@ public final class Year
case YEAR: return year;
case ERA: return (year < 1 ? 0 : 1);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......@@ -575,7 +615,7 @@ public final class Year
case YEAR: return Year.of((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : Year.of(1 - year));
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
......@@ -664,7 +704,7 @@ public final class Year
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
......@@ -821,7 +861,7 @@ public final class Year
* The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code Year}.
* For example, the period in decades between two year can be calculated
* using {@code startYear.periodUntil(endYear, DECADES)}.
* using {@code startYear.until(endYear, DECADES)}.
* <p>
* The calculation returns a whole number, representing the number of
* complete units between the two years.
......@@ -833,7 +873,7 @@ public final class Year
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, YEARS);
* amount = start.until(end, YEARS);
* amount = YEARS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -858,7 +898,7 @@ public final class Year
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endYear, TemporalUnit unit) {
public long until(Temporal endYear, TemporalUnit unit) {
if (endYear instanceof Year == false) {
Objects.requireNonNull(endYear, "endYear");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -873,7 +913,7 @@ public final class Year
case MILLENNIA: return yearsUntil / 1000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endYear);
}
......
......@@ -66,7 +66,12 @@ import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import static java.time.temporal.ChronoUnit.CENTURIES;
import static java.time.temporal.ChronoUnit.DECADES;
import static java.time.temporal.ChronoUnit.ERAS;
import static java.time.temporal.ChronoUnit.MILLENNIA;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.YEARS;
import java.io.DataInput;
import java.io.DataOutput;
......@@ -313,8 +318,9 @@ public final class YearMonth
* Checks if the specified field is supported.
* <p>
* This checks if this year-month can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -344,6 +350,42 @@ public final class YearMonth
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code MONTHS}
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
public boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit == MONTHS || unit == YEARS || unit == DECADES || unit == CENTURIES || unit == MILLENNIA || unit == ERAS;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -440,7 +482,7 @@ public final class YearMonth
case YEAR: return year;
case ERA: return (year < 1 ? 0 : 1);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......@@ -639,7 +681,7 @@ public final class YearMonth
case YEAR: return withYear((int) newValue);
case ERA: return (getLong(ERA) == newValue ? this : withYear(1 - year));
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.adjustInto(this, newValue);
}
......@@ -761,7 +803,7 @@ public final class YearMonth
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.addTo(this, amountToAdd);
}
......@@ -952,7 +994,7 @@ public final class YearMonth
* The result will be negative if the end is before the start.
* The {@code Temporal} passed to this method must be a {@code YearMonth}.
* For example, the period in years between two year-months can be calculated
* using {@code startYearMonth.periodUntil(endYearMonth, YEARS)}.
* using {@code startYearMonth.until(endYearMonth, YEARS)}.
* <p>
* The calculation returns a whole number, representing the number of
* complete units between the two year-months.
......@@ -964,7 +1006,7 @@ public final class YearMonth
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -989,7 +1031,7 @@ public final class YearMonth
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endYearMonth, TemporalUnit unit) {
public long until(Temporal endYearMonth, TemporalUnit unit) {
if (endYearMonth instanceof YearMonth == false) {
Objects.requireNonNull(endYearMonth, "endYearMonth");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -1005,7 +1047,7 @@ public final class YearMonth
case MILLENNIA: return monthsUntil / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endYearMonth);
}
......
......@@ -400,6 +400,36 @@ public abstract class ZoneId implements Serializable {
return of(zoneId, true);
}
/**
* Obtains an instance of {@code ZoneId} wrapping an offset.
* <p>
* If the prefix is "GMT", "UTC", or "UT" a {@code ZoneId}
* with the prefix and the non-zero offset is returned.
* If the prefix is empty {@code ""} the {@code ZoneOffset} is returned.
*
* @param prefix the time-zone ID, not null
* @param offset the offset, not null
* @return the zone ID, not null
* @throws IllegalArgumentException if the prefix is not one of
* "GMT", "UTC", or "UT", or ""
*/
public static ZoneId ofOffset(String prefix, ZoneOffset offset) {
Objects.requireNonNull(prefix, "prefix");
Objects.requireNonNull(offset, "offset");
if (prefix.length() == 0) {
return offset;
}
if (!prefix.equals("GMT") && !prefix.equals("UTC") && !prefix.equals("UT")) {
throw new IllegalArgumentException("prefix should be GMT, UTC or UT, is: " + prefix);
}
if (offset.getTotalSeconds() != 0) {
prefix = prefix.concat(offset.getId());
}
return new ZoneRegion(prefix, offset.getRules());
}
/**
* Parses the ID, taking a flag to indicate whether {@code ZoneRulesException}
* should be thrown or not, used in deserialization.
......@@ -433,7 +463,7 @@ public abstract class ZoneId implements Serializable {
private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) {
String prefix = zoneId.substring(0, prefixLength);
if (zoneId.length() == prefixLength) {
return ZoneRegion.ofPrefixedOffset(prefix, ZoneOffset.UTC);
return ofOffset(prefix, ZoneOffset.UTC);
}
if (zoneId.charAt(prefixLength) != '+' && zoneId.charAt(prefixLength) != '-') {
return ZoneRegion.ofId(zoneId, checkAvailable); // drop through to ZoneRulesProvider
......@@ -441,9 +471,9 @@ public abstract class ZoneId implements Serializable {
try {
ZoneOffset offset = ZoneOffset.of(zoneId.substring(prefixLength));
if (offset == ZoneOffset.UTC) {
return ZoneRegion.ofPrefixedOffset(prefix, offset);
return ofOffset(prefix, offset);
}
return ZoneRegion.ofPrefixedOffset(prefix + offset.toString(), offset);
return ofOffset(prefix, offset);
} catch (DateTimeException ex) {
throw new DateTimeException("Invalid ID for offset-based ZoneId: " + zoneId, ex);
}
......
......@@ -61,7 +61,6 @@
*/
package java.time;
import java.time.temporal.UnsupportedTemporalTypeException;
import static java.time.LocalTime.MINUTES_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_HOUR;
import static java.time.LocalTime.SECONDS_PER_MINUTE;
......@@ -79,6 +78,7 @@ import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQuery;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.time.zone.ZoneRules;
import java.util.Objects;
......@@ -581,7 +581,7 @@ public final class ZoneOffset
if (field == OFFSET_SECONDS) {
return totalSeconds;
} else if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return range(field).checkValidIntValue(getLong(field), field);
}
......@@ -613,7 +613,7 @@ public final class ZoneOffset
if (field == OFFSET_SECONDS) {
return totalSeconds;
} else if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......
......@@ -66,7 +66,6 @@ import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesException;
import java.time.zone.ZoneRulesProvider;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* A geographical region where the same time-zone rules apply.
......@@ -153,19 +152,6 @@ final class ZoneRegion extends ZoneId implements Serializable {
}
}
/**
* Obtains an instance of {@code ZoneId} wrapping an offset.
* <p>
* For example, zone IDs like 'UTC', 'GMT', 'UT' and 'UTC+01:30' will be setup here.
*
* @param zoneId the time-zone ID, not null
* @param offset the offset, not null
* @return the zone ID, not null
*/
static ZoneRegion ofPrefixedOffset(String zoneId, ZoneOffset offset) {
return new ZoneRegion(zoneId, offset.getRules());
}
//-------------------------------------------------------------------------
/**
* Constructor.
......
......@@ -642,8 +642,9 @@ public final class ZonedDateTime
* Checks if the specified field is supported.
* <p>
* This checks if this date-time can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
......@@ -694,6 +695,48 @@ public final class ZonedDateTime
return field instanceof ChronoField || (field != null && field.isSupportedBy(this));
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to, or subtracted from, this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* If the unit is a {@link ChronoUnit} then the query is implemented here.
* The supported units are:
* <ul>
* <li>{@code NANOS}
* <li>{@code MICROS}
* <li>{@code MILLIS}
* <li>{@code SECONDS}
* <li>{@code MINUTES}
* <li>{@code HOURS}
* <li>{@code HALF_DAYS}
* <li>{@code DAYS}
* <li>{@code WEEKS}
* <li>{@code MONTHS}
* <li>{@code YEARS}
* <li>{@code DECADES}
* <li>{@code CENTURIES}
* <li>{@code MILLENNIA}
* <li>{@code ERAS}
* </ul>
* All other {@code ChronoUnit} instances will return false.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override // override for Javadoc
public boolean isSupported(TemporalUnit unit) {
return ChronoZonedDateTime.super.isSupported(unit);
}
//-----------------------------------------------------------------------
/**
* Gets the range of valid values for the specified field.
* <p>
......@@ -1540,8 +1583,7 @@ public final class ZonedDateTime
@Override
public ZonedDateTime plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
ChronoUnit u = (ChronoUnit) unit;
if (u.isDateUnit()) {
if (unit.isDateBased()) {
return resolveLocal(dateTime.plus(amountToAdd, unit));
} else {
return resolveInstant(dateTime.plus(amountToAdd, unit));
......@@ -1990,7 +2032,7 @@ public final class ZonedDateTime
* The start and end points are {@code this} and the specified date-time.
* The result will be negative if the end is before the start.
* For example, the period in days between two date-times can be calculated
* using {@code startDateTime.periodUntil(endDateTime, DAYS)}.
* using {@code startDateTime.until(endDateTime, DAYS)}.
* <p>
* The {@code Temporal} passed to this method must be a {@code ZonedDateTime}.
* If the time-zone differs between the two zoned date-times, the specified
......@@ -2006,7 +2048,7 @@ public final class ZonedDateTime
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -2047,7 +2089,7 @@ public final class ZonedDateTime
* @throws ArithmeticException if numeric overflow occurs
*/
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ZonedDateTime == false) {
Objects.requireNonNull(endDateTime, "endDateTime");
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
......@@ -2055,11 +2097,10 @@ public final class ZonedDateTime
if (unit instanceof ChronoUnit) {
ZonedDateTime end = (ZonedDateTime) endDateTime;
end = end.withZoneSameInstant(zone);
ChronoUnit u = (ChronoUnit) unit;
if (u.isDateUnit()) {
return dateTime.periodUntil(end.dateTime, unit);
if (unit.isDateBased()) {
return dateTime.until(end.dateTime, unit);
} else {
return toOffsetDateTime().periodUntil(end.toOffsetDateTime(), unit);
return toOffsetDateTime().until(end.toOffsetDateTime(), unit);
}
}
return unit.between(this, endDateTime);
......
......@@ -67,6 +67,8 @@ import java.time.DateTimeException;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
......@@ -96,12 +98,12 @@ import java.util.Objects;
* // Enumerate the list of available calendars and print today for each
* Set&lt;Chronology&gt; chronos = Chronology.getAvailableChronologies();
* for (Chronology chrono : chronos) {
* ChronoLocalDate&lt;?&gt; date = chrono.dateNow();
* ChronoLocalDate date = chrono.dateNow();
* System.out.printf(" %20s: %s%n", chrono.getID(), date.toString());
* }
*
* // Print the Hijrah date and calendar
* ChronoLocalDate&lt;?&gt; date = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate date = Chronology.of("Hijrah").dateNow();
* int day = date.get(ChronoField.DAY_OF_MONTH);
* int dow = date.get(ChronoField.DAY_OF_WEEK);
* int month = date.get(ChronoField.MONTH_OF_YEAR);
......@@ -110,10 +112,10 @@ import java.util.Objects;
* dow, day, month, year);
* // Print today's date and the last day of the year
* ChronoLocalDate&lt;?&gt; now1 = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate&lt;?&gt; first = now1.with(ChronoField.DAY_OF_MONTH, 1)
* ChronoLocalDate now1 = Chronology.of("Hijrah").dateNow();
* ChronoLocalDate first = now1.with(ChronoField.DAY_OF_MONTH, 1)
* .with(ChronoField.MONTH_OF_YEAR, 1);
* ChronoLocalDate&lt;?&gt; last = first.plus(1, ChronoUnit.YEARS)
* ChronoLocalDate last = first.plus(1, ChronoUnit.YEARS)
* .minus(1, ChronoUnit.DAYS);
* System.out.printf(" Today is %s: start: %s; end: %s%n", last.getChronology().getID(),
* first, last);
......@@ -138,22 +140,61 @@ import java.util.Objects;
* @param <D> the ChronoLocalDate of this date-time
* @since 1.8
*/
abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
implements ChronoLocalDate<D>, Temporal, TemporalAdjuster, Serializable {
abstract class ChronoDateImpl<D extends ChronoLocalDate>
implements ChronoLocalDate, Temporal, TemporalAdjuster, Serializable {
/**
* Serialization version.
*/
private static final long serialVersionUID = 6282433883239719096L;
/**
* Casts the {@code Temporal} to {@code ChronoLocalDate} ensuring it bas the specified chronology.
*
* @param chrono the chronology to check for, not null
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoLocalDate}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDate
* or the chronology is not equal this Chronology
*/
static <D extends ChronoLocalDate> D ensureValid(Chronology chrono, Temporal temporal) {
@SuppressWarnings("unchecked")
D other = (D) temporal;
if (chrono.equals(other.getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, expected: " + chrono.getId() + ", actual: " + other.getChronology().getId());
}
return other;
}
//-----------------------------------------------------------------------
/**
* Creates an instance.
*/
ChronoDateImpl() {
}
@Override
@SuppressWarnings("unchecked")
public D with(TemporalAdjuster adjuster) {
return (D) ChronoLocalDate.super.with(adjuster);
}
@Override
@SuppressWarnings("unchecked")
public D with(TemporalField field, long value) {
return (D) ChronoLocalDate.super.with(field, value);
}
//-----------------------------------------------------------------------
@Override
@SuppressWarnings("unchecked")
public D plus(TemporalAmount amount) {
return (D) ChronoLocalDate.super.plus(amount);
}
//-----------------------------------------------------------------------
@Override
@SuppressWarnings("unchecked")
public D plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
......@@ -167,9 +208,21 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
case MILLENNIA: return plusYears(Math.multiplyExact(amountToAdd, 1000));
case ERAS: return with(ERA, Math.addExact(getLong(ERA), amountToAdd));
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return ChronoLocalDate.super.plus(amountToAdd, unit);
return (D) ChronoLocalDate.super.plus(amountToAdd, unit);
}
@Override
@SuppressWarnings("unchecked")
public D minus(TemporalAmount amount) {
return (D) ChronoLocalDate.super.minus(amount);
}
@Override
@SuppressWarnings("unchecked")
public D minus(long amountToSubtract, TemporalUnit unit) {
return (D) ChronoLocalDate.super.minus(amountToSubtract, unit);
}
//-----------------------------------------------------------------------
......@@ -254,6 +307,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
* @return a date based on this one with the years subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
@SuppressWarnings("unchecked")
D minusYears(long yearsToSubtract) {
return (yearsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusYears(Long.MAX_VALUE)).plusYears(1) : plusYears(-yearsToSubtract));
}
......@@ -274,6 +328,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
* @return a date based on this one with the months subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
@SuppressWarnings("unchecked")
D minusMonths(long monthsToSubtract) {
return (monthsToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusMonths(Long.MAX_VALUE)).plusMonths(1) : plusMonths(-monthsToSubtract));
}
......@@ -293,6 +348,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
* @return a date based on this one with the weeks subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
@SuppressWarnings("unchecked")
D minusWeeks(long weeksToSubtract) {
return (weeksToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusWeeks(Long.MAX_VALUE)).plusWeeks(1) : plusWeeks(-weeksToSubtract));
}
......@@ -310,6 +366,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
* @return a date based on this one with the days subtracted, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
@SuppressWarnings("unchecked")
D minusDays(long daysToSubtract) {
return (daysToSubtract == Long.MIN_VALUE ? ((ChronoDateImpl<D>)plusDays(Long.MAX_VALUE)).plusDays(1) : plusDays(-daysToSubtract));
}
......@@ -321,13 +378,13 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
Objects.requireNonNull(endDateTime, "endDateTime");
Objects.requireNonNull(unit, "unit");
if (endDateTime instanceof ChronoLocalDate == false) {
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
}
ChronoLocalDate<?> end = (ChronoLocalDate<?>) endDateTime;
ChronoLocalDate end = (ChronoLocalDate) endDateTime;
if (getChronology().equals(end.getChronology()) == false) {
throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
}
......@@ -342,16 +399,16 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
case MILLENNIA: return monthsUntil(end) / 12000;
case ERAS: return end.getLong(ERA) - getLong(ERA);
}
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return unit.between(this, endDateTime);
}
private long daysUntil(ChronoLocalDate<?> end) {
private long daysUntil(ChronoLocalDate end) {
return end.toEpochDay() - toEpochDay(); // no overflow
}
private long monthsUntil(ChronoLocalDate<?> end) {
private long monthsUntil(ChronoLocalDate end) {
ValueRange range = getChronology().range(MONTH_OF_YEAR);
if (range.getMaximum() != 12) {
throw new IllegalStateException("ChronoDateImpl only supports Chronologies with 12 months per year");
......@@ -367,7 +424,7 @@ abstract class ChronoDateImpl<D extends ChronoLocalDate<D>>
return true;
}
if (obj instanceof ChronoLocalDate) {
return compareTo((ChronoLocalDate<?>) obj) == 0;
return compareTo((ChronoLocalDate) obj) == 0;
}
return false;
}
......
......@@ -242,11 +242,10 @@ import java.util.Objects;
* Additional calendar systems may be added to the system.
* See {@link Chronology} for more details.
*
* @param <D> the concrete type for the date
* @since 1.8
*/
public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate<?>> {
public interface ChronoLocalDate
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDate> {
/**
* Gets a comparator that compares {@code ChronoLocalDate} in
......@@ -263,7 +262,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @see #isBefore
* @see #isEqual
*/
static Comparator<ChronoLocalDate<?>> timeLineOrder() {
static Comparator<ChronoLocalDate> timeLineOrder() {
return Chronology.DATE_ORDER;
}
......@@ -289,9 +288,9 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws DateTimeException if unable to convert to a {@code ChronoLocalDate}
* @see Chronology#date(TemporalAccessor)
*/
static ChronoLocalDate<?> from(TemporalAccessor temporal) {
static ChronoLocalDate from(TemporalAccessor temporal) {
if (temporal instanceof ChronoLocalDate) {
return (ChronoLocalDate<?>) temporal;
return (ChronoLocalDate) temporal;
}
Chronology chrono = temporal.query(TemporalQuery.chronology());
if (chrono == null) {
......@@ -367,6 +366,25 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
return (isLeapYear() ? 366 : 365);
}
/**
* Checks if the specified field is supported.
* <p>
* This checks if the specified field can be queried on this date.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* The set of supported fields is defined by the chronology and normally includes
* all {@code ChronoField} date fields.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field can be queried, false if not
*/
@Override
default boolean isSupported(TemporalField field) {
if (field instanceof ChronoField) {
......@@ -375,6 +393,32 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
return field != null && field.isSupportedBy(this);
}
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to or subtracted from this date.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* The set of supported units is defined by the chronology and normally includes
* all {@code ChronoUnit} date units except {@code FOREVER}.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
default boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit.isDateBased();
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
// override for covariant return type
/**
......@@ -383,8 +427,8 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D with(TemporalAdjuster adjuster) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.with(adjuster));
default ChronoLocalDate with(TemporalAdjuster adjuster) {
return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.with(adjuster));
}
/**
......@@ -394,11 +438,11 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D with(TemporalField field, long newValue) {
default ChronoLocalDate with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return (D) getChronology().ensureChronoLocalDate(field.adjustInto(this, newValue));
return ChronoDateImpl.ensureValid(getChronology(), field.adjustInto(this, newValue));
}
/**
......@@ -407,8 +451,8 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D plus(TemporalAmount amount) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.plus(amount));
default ChronoLocalDate plus(TemporalAmount amount) {
return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.plus(amount));
}
/**
......@@ -417,11 +461,11 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D plus(long amountToAdd, TemporalUnit unit) {
default ChronoLocalDate plus(long amountToAdd, TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit.getName());
throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
}
return (D) getChronology().ensureChronoLocalDate(unit.addTo(this, amountToAdd));
return ChronoDateImpl.ensureValid(getChronology(), unit.addTo(this, amountToAdd));
}
/**
......@@ -430,8 +474,8 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D minus(TemporalAmount amount) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amount));
default ChronoLocalDate minus(TemporalAmount amount) {
return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amount));
}
/**
......@@ -441,8 +485,8 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException {@inheritDoc}
*/
@Override
default D minus(long amountToSubtract, TemporalUnit unit) {
return (D) getChronology().ensureChronoLocalDate(Temporal.super.minus(amountToSubtract, unit));
default ChronoLocalDate minus(long amountToSubtract, TemporalUnit unit) {
return ChronoDateImpl.ensureValid(getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
......@@ -522,14 +566,14 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* The calculation returns a whole number, representing the number of
* complete units between the two dates.
* For example, the amount in days between two dates can be calculated
* using {@code startDate.periodUntil(endDate, DAYS)}.
* using {@code startDate.until(endDate, DAYS)}.
* <p>
* There are two equivalent ways of using this method.
* The first is to invoke this method.
* The second is to use {@link TemporalUnit#between(Temporal, Temporal)}:
* <pre>
* // these two lines are equivalent
* amount = start.periodUntil(end, MONTHS);
* amount = start.until(end, MONTHS);
* amount = MONTHS.between(start, end);
* </pre>
* The choice should be made based on which makes the code more readable.
......@@ -555,7 +599,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws ArithmeticException if numeric overflow occurs
*/
@Override // override for Javadoc
long periodUntil(Temporal endDate, TemporalUnit unit);
long until(Temporal endDate, TemporalUnit unit);
/**
* Calculates the period between this date and another date as a {@code Period}.
......@@ -575,7 +619,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @throws DateTimeException if the period cannot be calculated
* @throws ArithmeticException if numeric overflow occurs
*/
Period periodUntil(ChronoLocalDate<?> endDate);
Period until(ChronoLocalDate endDate);
/**
* Formats this date using the specified formatter.
......@@ -606,8 +650,9 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @param localTime the local time to use, not null
* @return the local date-time formed from this date and the specified time, not null
*/
default ChronoLocalDateTime<D> atTime(LocalTime localTime) {
return (ChronoLocalDateTime<D>)ChronoLocalDateTimeImpl.of(this, localTime);
@SuppressWarnings("unchecked")
default ChronoLocalDateTime<?> atTime(LocalTime localTime) {
return ChronoLocalDateTimeImpl.of(this, localTime);
}
//-----------------------------------------------------------------------
......@@ -656,7 +701,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @return the comparator value, negative if less, positive if greater
*/
@Override
default int compareTo(ChronoLocalDate<?> other) {
default int compareTo(ChronoLocalDate other) {
int cmp = Long.compare(toEpochDay(), other.toEpochDay());
if (cmp == 0) {
cmp = getChronology().compareTo(other.getChronology());
......@@ -678,7 +723,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @param other the other date to compare to, not null
* @return true if this is after the specified date
*/
default boolean isAfter(ChronoLocalDate<?> other) {
default boolean isAfter(ChronoLocalDate other) {
return this.toEpochDay() > other.toEpochDay();
}
......@@ -696,7 +741,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @param other the other date to compare to, not null
* @return true if this is before the specified date
*/
default boolean isBefore(ChronoLocalDate<?> other) {
default boolean isBefore(ChronoLocalDate other) {
return this.toEpochDay() < other.toEpochDay();
}
......@@ -714,7 +759,7 @@ public interface ChronoLocalDate<D extends ChronoLocalDate<D>>
* @param other the other date to compare to, not null
* @return true if the underlying date is equal to the specified date
*/
default boolean isEqual(ChronoLocalDate<?> other) {
default boolean isEqual(ChronoLocalDate other) {
return this.toEpochDay() == other.toEpochDay();
}
......
......@@ -63,6 +63,7 @@ package java.time.chrono;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.NANO_OF_DAY;
import static java.time.temporal.ChronoUnit.FOREVER;
import static java.time.temporal.ChronoUnit.NANOS;
import java.time.DateTimeException;
......@@ -73,6 +74,7 @@ import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -114,7 +116,7 @@ import java.util.Objects;
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
public interface ChronoLocalDateTime<D extends ChronoLocalDate>
extends Temporal, TemporalAdjuster, Comparable<ChronoLocalDateTime<?>> {
/**
......@@ -191,9 +193,54 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
*/
LocalTime toLocalTime();
@Override // Override to provide javadoc
/**
* Checks if the specified field is supported.
* <p>
* This checks if the specified field can be queried on this date-time.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* The set of supported fields is defined by the chronology and normally includes
* all {@code ChronoField} date and time fields.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field can be queried, false if not
*/
@Override
boolean isSupported(TemporalField field);
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to or subtracted from this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* The set of supported units is defined by the chronology and normally includes
* all {@code ChronoUnit} units except {@code FOREVER}.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
default boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit != FOREVER;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
// override for covariant return type
/**
......@@ -203,7 +250,7 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoLocalDateTime<D> with(TemporalAdjuster adjuster) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.with(adjuster)));
return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster));
}
/**
......@@ -221,7 +268,7 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoLocalDateTime<D> plus(TemporalAmount amount) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.plus(amount)));
return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount));
}
/**
......@@ -239,7 +286,7 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoLocalDateTime<D> minus(TemporalAmount amount) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amount)));
return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount));
}
/**
......@@ -249,7 +296,7 @@ public interface ChronoLocalDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoLocalDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
return (ChronoLocalDateTime<D>)(toLocalDate().getChronology().ensureChronoLocalDateTime(Temporal.super.minus(amountToSubtract, unit)));
return ChronoLocalDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
......
......@@ -98,7 +98,7 @@ import java.util.Objects;
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate>
implements ChronoLocalDateTime<D>, Temporal, TemporalAdjuster, Serializable {
/**
......@@ -171,9 +171,27 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
* @param time the local time, not null
* @return the local date-time, not null
*/
@SuppressWarnings("rawtypes")
static ChronoLocalDateTimeImpl<?> of(ChronoLocalDate<?> date, LocalTime time) {
return new ChronoLocalDateTimeImpl(date, time);
static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> of(R date, LocalTime time) {
return new ChronoLocalDateTimeImpl<>(date, time);
}
/**
* Casts the {@code Temporal} to {@code ChronoLocalDateTime} ensuring it bas the specified chronology.
*
* @param chrono the chronology to check for, not null
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoLocalDateTime}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoLocalDateTimeImpl
* or the chronology is not equal this Chronology
*/
static <R extends ChronoLocalDate> ChronoLocalDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoLocalDateTimeImpl<R> other = (ChronoLocalDateTimeImpl<R>) temporal;
if (chrono.equals(other.toLocalDate().getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
+ ", actual: " + other.toLocalDate().getChronology().getId());
}
return other;
}
/**
......@@ -202,7 +220,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
return this;
}
// Validate that the new Temporal is a ChronoLocalDate (and not something else)
D cd = (D) date.getChronology().ensureChronoLocalDate(newDate);
D cd = ChronoDateImpl.ensureValid(date.getChronology(), newDate);
return new ChronoLocalDateTimeImpl<>(cd, newTime);
}
......@@ -260,13 +278,13 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
public ChronoLocalDateTimeImpl<D> with(TemporalAdjuster adjuster) {
if (adjuster instanceof ChronoLocalDate) {
// The Chronology is checked in with(date,time)
return with((ChronoLocalDate<D>) adjuster, time);
return with((ChronoLocalDate) adjuster, time);
} else if (adjuster instanceof LocalTime) {
return with(date, (LocalTime) adjuster);
} else if (adjuster instanceof ChronoLocalDateTimeImpl) {
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster));
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster);
}
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime((ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this)));
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), (ChronoLocalDateTimeImpl<?>) adjuster.adjustInto(this));
}
@Override
......@@ -279,7 +297,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
return with(date.with(field, newValue), time);
}
}
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(field.adjustInto(this, newValue)));
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), field.adjustInto(this, newValue));
}
//-----------------------------------------------------------------------
......@@ -298,7 +316,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
}
return with(date.plus(amountToAdd, unit), time);
}
return (ChronoLocalDateTimeImpl<D>)(date.getChronology().ensureChronoLocalDateTime(unit.addTo(this, amountToAdd)));
return ChronoLocalDateTimeImpl.ensureValid(date.getChronology(), unit.addTo(this, amountToAdd));
}
private ChronoLocalDateTimeImpl<D> plusDays(long days) {
......@@ -322,7 +340,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
}
//-----------------------------------------------------------------------
private ChronoLocalDateTimeImpl<D> plusWithOverflow(ChronoLocalDate<?> newDate, long hours, long minutes, long seconds, long nanos) {
private ChronoLocalDateTimeImpl<D> plusWithOverflow(D newDate, long hours, long minutes, long seconds, long nanos) {
// 9223372036854775808 long, 2147483648 int
if ((hours | minutes | seconds | nanos) == 0) {
return with(newDate, time);
......@@ -351,7 +369,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
//-----------------------------------------------------------------------
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ChronoLocalDateTime == false) {
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
}
......@@ -361,10 +379,9 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
throw new DateTimeException("Unable to calculate amount as objects have different chronologies");
}
if (unit instanceof ChronoUnit) {
ChronoUnit f = (ChronoUnit) unit;
if (f.isTimeUnit()) {
if (unit.isTimeBased()) {
long amount = end.getLong(EPOCH_DAY) - date.getLong(EPOCH_DAY);
switch (f) {
switch ((ChronoUnit) unit) {
case NANOS: amount = Math.multiplyExact(amount, NANOS_PER_DAY); break;
case MICROS: amount = Math.multiplyExact(amount, MICROS_PER_DAY); break;
case MILLIS: amount = Math.multiplyExact(amount, MILLIS_PER_DAY); break;
......@@ -373,13 +390,13 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
case HOURS: amount = Math.multiplyExact(amount, HOURS_PER_DAY); break;
case HALF_DAYS: amount = Math.multiplyExact(amount, 2); break;
}
return Math.addExact(amount, time.periodUntil(end.toLocalTime(), unit));
return Math.addExact(amount, time.until(end.toLocalTime(), unit));
}
D endDate = end.toLocalDate();
ChronoLocalDate endDate = end.toLocalDate();
if (end.toLocalTime().isBefore(time)) {
endDate = endDate.minus(1, ChronoUnit.DAYS);
}
return date.periodUntil(endDate, unit);
return date.until(endDate, unit);
}
return unit.between(this, endDateTime);
}
......@@ -404,7 +421,7 @@ final class ChronoLocalDateTimeImpl<D extends ChronoLocalDate<D>>
}
static ChronoLocalDateTime<?> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
ChronoLocalDate<?> date = (ChronoLocalDate<?>) in.readObject();
ChronoLocalDate date = (ChronoLocalDate) in.readObject();
LocalTime time = (LocalTime) in.readObject();
return date.atTime(time);
}
......
......@@ -63,6 +63,7 @@ package java.time.chrono;
import static java.time.temporal.ChronoField.INSTANT_SECONDS;
import static java.time.temporal.ChronoField.OFFSET_SECONDS;
import static java.time.temporal.ChronoUnit.FOREVER;
import static java.time.temporal.ChronoUnit.NANOS;
import java.time.DateTimeException;
......@@ -73,6 +74,7 @@ import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
......@@ -115,7 +117,7 @@ import java.util.Objects;
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
public interface ChronoZonedDateTime<D extends ChronoLocalDate>
extends Temporal, Comparable<ChronoZonedDateTime<?>> {
/**
......@@ -338,9 +340,54 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
*/
ChronoZonedDateTime<D> withZoneSameInstant(ZoneId zone);
@Override // Override to provide javadoc
/**
* Checks if the specified field is supported.
* <p>
* This checks if the specified field can be queried on this date-time.
* If false, then calling the {@link #range(TemporalField) range},
* {@link #get(TemporalField) get} and {@link #with(TemporalField, long)}
* methods will throw an exception.
* <p>
* The set of supported fields is defined by the chronology and normally includes
* all {@code ChronoField} fields.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field can be queried, false if not
*/
@Override
boolean isSupported(TemporalField field);
/**
* Checks if the specified unit is supported.
* <p>
* This checks if the specified unit can be added to or subtracted from this date-time.
* If false, then calling the {@link #plus(long, TemporalUnit)} and
* {@link #minus(long, TemporalUnit) minus} methods will throw an exception.
* <p>
* The set of supported units is defined by the chronology and normally includes
* all {@code ChronoUnit} units except {@code FOREVER}.
* <p>
* If the unit is not a {@code ChronoUnit}, then the result of this method
* is obtained by invoking {@code TemporalUnit.isSupportedBy(Temporal)}
* passing {@code this} as the argument.
* Whether the unit is supported is determined by the unit.
*
* @param unit the unit to check, null returns false
* @return true if the unit can be added/subtracted, false if not
*/
@Override
default boolean isSupported(TemporalUnit unit) {
if (unit instanceof ChronoUnit) {
return unit != FOREVER;
}
return unit != null && unit.isSupportedBy(this);
}
//-----------------------------------------------------------------------
// override for covariant return type
/**
......@@ -350,7 +397,7 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoZonedDateTime<D> with(TemporalAdjuster adjuster) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.with(adjuster)));
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.with(adjuster));
}
/**
......@@ -368,7 +415,7 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoZonedDateTime<D> plus(TemporalAmount amount) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.plus(amount)));
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.plus(amount));
}
/**
......@@ -386,7 +433,7 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoZonedDateTime<D> minus(TemporalAmount amount) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amount)));
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amount));
}
/**
......@@ -396,7 +443,7 @@ public interface ChronoZonedDateTime<D extends ChronoLocalDate<D>>
*/
@Override
default ChronoZonedDateTime<D> minus(long amountToSubtract, TemporalUnit unit) {
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(Temporal.super.minus(amountToSubtract, unit)));
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), Temporal.super.minus(amountToSubtract, unit));
}
//-----------------------------------------------------------------------
......
......@@ -101,7 +101,7 @@ import java.util.Objects;
* @param <D> the concrete type for the date of this date-time
* @since 1.8
*/
final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate>
implements ChronoZonedDateTime<D>, Serializable {
/**
......@@ -131,7 +131,7 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
* @param preferredOffset the zone offset, null if no preference
* @return the zoned date-time, not null
*/
static <R extends ChronoLocalDate<R>> ChronoZonedDateTime<R> ofBest(
static <R extends ChronoLocalDate> ChronoZonedDateTime<R> ofBest(
ChronoLocalDateTimeImpl<R> localDateTime, ZoneId zone, ZoneOffset preferredOffset) {
Objects.requireNonNull(localDateTime, "localDateTime");
Objects.requireNonNull(zone, "zone");
......@@ -167,14 +167,13 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
* @param zone the zone identifier, not null
* @return the zoned date-time, not null
*/
@SuppressWarnings("rawtypes")
static ChronoZonedDateTimeImpl<?> ofInstant(Chronology chrono, Instant instant, ZoneId zone) {
ZoneRules rules = zone.getRules();
ZoneOffset offset = rules.getOffset(instant);
Objects.requireNonNull(offset, "offset"); // protect against bad ZoneRules
LocalDateTime ldt = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), instant.getNano(), offset);
ChronoLocalDateTimeImpl<?> cldt = (ChronoLocalDateTimeImpl<?>) chrono.localDateTime(ldt);
return new ChronoZonedDateTimeImpl(cldt, offset, zone);
ChronoLocalDateTimeImpl<?> cldt = (ChronoLocalDateTimeImpl<?>)chrono.localDateTime(ldt);
return new ChronoZonedDateTimeImpl<>(cldt, offset, zone);
}
/**
......@@ -184,10 +183,30 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
* @param zone the time-zone to use, validated not null
* @return the zoned date-time, validated not null
*/
@SuppressWarnings("unchecked")
private ChronoZonedDateTimeImpl<D> create(Instant instant, ZoneId zone) {
return (ChronoZonedDateTimeImpl<D>)ofInstant(toLocalDate().getChronology(), instant, zone);
}
/**
* Casts the {@code Temporal} to {@code ChronoZonedDateTimeImpl} ensuring it bas the specified chronology.
*
* @param chrono the chronology to check for, not null
* @param temporal a date-time to cast, not null
* @return the date-time checked and cast to {@code ChronoZonedDateTimeImpl}, not null
* @throws ClassCastException if the date-time cannot be cast to ChronoZonedDateTimeImpl
* or the chronology is not equal this Chronology
*/
static <R extends ChronoLocalDate> ChronoZonedDateTimeImpl<R> ensureValid(Chronology chrono, Temporal temporal) {
@SuppressWarnings("unchecked")
ChronoZonedDateTimeImpl<R> other = (ChronoZonedDateTimeImpl<R>) temporal;
if (chrono.equals(other.toLocalDate().getChronology()) == false) {
throw new ClassCastException("Chronology mismatch, required: " + chrono.getId()
+ ", actual: " + other.toLocalDate().getChronology().getId());
}
return other;
}
//-----------------------------------------------------------------------
/**
* Constructor.
......@@ -271,7 +290,7 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
}
return ofBest(dateTime.with(field, newValue), zone, offset);
}
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(field.adjustInto(this, newValue)));
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), field.adjustInto(this, newValue));
}
//-----------------------------------------------------------------------
......@@ -280,12 +299,12 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
if (unit instanceof ChronoUnit) {
return with(dateTime.plus(amountToAdd, unit));
}
return (ChronoZonedDateTime<D>)(toLocalDate().getChronology().ensureChronoZonedDateTime(unit.addTo(this, amountToAdd))); /// TODO: Generics replacement Risk!
return ChronoZonedDateTimeImpl.ensureValid(toLocalDate().getChronology(), unit.addTo(this, amountToAdd)); /// TODO: Generics replacement Risk!
}
//-----------------------------------------------------------------------
@Override
public long periodUntil(Temporal endDateTime, TemporalUnit unit) {
public long until(Temporal endDateTime, TemporalUnit unit) {
if (endDateTime instanceof ChronoZonedDateTime == false) {
throw new DateTimeException("Unable to calculate amount as objects are of two different types");
}
......@@ -296,7 +315,7 @@ final class ChronoZonedDateTimeImpl<D extends ChronoLocalDate<D>>
}
if (unit instanceof ChronoUnit) {
end = end.withZoneSameInstant(offset);
return dateTime.periodUntil(end.toLocalDateTime(), unit);
return dateTime.until(end.toLocalDateTime(), unit);
}
return unit.between(this, endDateTime);
}
......
......@@ -238,7 +238,7 @@ public interface Era extends TemporalAccessor, TemporalAdjuster {
if (field == ERA) {
return getValue();
} else if (field instanceof ChronoField) {
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......
......@@ -71,8 +71,10 @@ import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.HashMap;
......@@ -115,7 +117,7 @@ import sun.util.logging.PlatformLogger;
* <tr class="altColor">
* <td>Hijrah-umalqura</td>
* <td>islamic-umalqura</td>
* <td>ca-islamic-cv-umalqura</td>
* <td>ca-islamic-umalqura</td>
* <td>Islamic - Umm Al-Qura calendar of Saudi Arabia</td>
* </tr>
* </tbody>
......@@ -126,10 +128,10 @@ import sun.util.logging.PlatformLogger;
* <p>
* Selecting the chronology from the locale uses {@link Chronology#ofLocale}
* to find the Chronology based on Locale supported BCP 47 extension mechanism
* to request a specific calendar ("ca") and variant ("cv"). For example,
* to request a specific calendar ("ca"). For example,
* </p>
* <pre>
* Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-cv-umalqura");
* Locale locale = Locale.forLanguageTag("en-US-u-ca-islamic-umalqura");
* Chronology chrono = Chronology.ofLocale(locale);
* </pre>
*
......@@ -472,11 +474,16 @@ public final class HijrahChronology extends Chronology implements Serializable {
* @param prolepticYear the proleptic-year
* @param dayOfYear the day-of-year
* @return the Hijrah local date, not null
* @throws DateTimeException if unable to create the date
* @throws DateTimeException if the value of the year is out of range,
* or if the day-of-year is invalid for the year
*/
@Override
public HijrahDate dateYearDay(int prolepticYear, int dayOfYear) {
return HijrahDate.of(this, prolepticYear, 1, 1).plusDays(dayOfYear - 1); // TODO better
HijrahDate date = HijrahDate.of(this, prolepticYear, 1, 1);
if (dayOfYear > date.lengthOfYear()) {
throw new DateTimeException("Invalid dayOfYear: " + dayOfYear);
}
return date.plusDays(dayOfYear - 1);
}
/**
......@@ -515,16 +522,19 @@ public final class HijrahChronology extends Chronology implements Serializable {
}
@Override
@SuppressWarnings("unchecked")
public ChronoLocalDateTime<HijrahDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<HijrahDate>) super.localDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<HijrahDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<HijrahDate>) super.zonedDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<HijrahDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<HijrahDate>) super.zonedDateTime(instant, zone);
}
......@@ -550,7 +560,7 @@ public final class HijrahChronology extends Chronology implements Serializable {
}
@Override
public Era eraOf(int eraValue) {
public HijrahEra eraOf(int eraValue) {
switch (eraValue) {
case 1:
return HijrahEra.AH;
......@@ -580,6 +590,8 @@ public final class HijrahChronology extends Chronology implements Serializable {
case YEAR:
case YEAR_OF_ERA:
return ValueRange.of(getMinimumYear(), getMaximumYear());
case ERA:
return ValueRange.of(1, 1);
default:
return field.range();
}
......@@ -587,6 +599,13 @@ public final class HijrahChronology extends Chronology implements Serializable {
return field.range();
}
//-----------------------------------------------------------------------
@Override // override for return type
public HijrahDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
return (HijrahDate) super.resolveDate(fieldValues, resolverStyle);
}
//-----------------------------------------------------------------------
/**
* Check the validity of a year.
*
......
......@@ -109,7 +109,7 @@ import java.time.temporal.ValueRange;
*/
public final class HijrahDate
extends ChronoDateImpl<HijrahDate>
implements ChronoLocalDate<HijrahDate>, Serializable {
implements ChronoLocalDate, Serializable {
/**
* Serialization version.
......@@ -204,7 +204,7 @@ public final class HijrahDate
* @throws DateTimeException if the current date cannot be obtained
*/
public static HijrahDate now(Clock clock) {
return HijrahChronology.INSTANCE.date(LocalDate.now(clock));
return HijrahDate.ofEpochDay(HijrahChronology.INSTANCE, LocalDate.now(clock).toEpochDay());
}
/**
......@@ -349,7 +349,7 @@ public final class HijrahDate
}
return getChronology().range(f);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.rangeRefinedBy(this);
}
......@@ -372,7 +372,7 @@ public final class HijrahDate
case YEAR: return prolepticYear;
case ERA: return getEraValue();
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.getFrom(this);
}
......@@ -393,7 +393,7 @@ public final class HijrahDate
case ALIGNED_DAY_OF_WEEK_IN_MONTH: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_MONTH));
case ALIGNED_DAY_OF_WEEK_IN_YEAR: return plusDays(newValue - getLong(ALIGNED_DAY_OF_WEEK_IN_YEAR));
case DAY_OF_MONTH: return resolvePreviousValid(prolepticYear, monthOfYear, nvalue);
case DAY_OF_YEAR: return resolvePreviousValid(prolepticYear, ((nvalue - 1) / 30) + 1, ((nvalue - 1) % 30) + 1);
case DAY_OF_YEAR: return plusDays(Math.min(nvalue, lengthOfYear()) - getDayOfYear());
case EPOCH_DAY: return new HijrahDate(chrono, newValue);
case ALIGNED_WEEK_OF_MONTH: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_MONTH)) * 7);
case ALIGNED_WEEK_OF_YEAR: return plusDays((newValue - getLong(ALIGNED_WEEK_OF_YEAR)) * 7);
......@@ -403,9 +403,9 @@ public final class HijrahDate
case YEAR: return resolvePreviousValid(nvalue, monthOfYear, dayOfMonth);
case ERA: return resolvePreviousValid(1 - prolepticYear, monthOfYear, dayOfMonth);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return ChronoLocalDate.super.with(field, newValue);
return super.with(field, newValue);
}
private HijrahDate resolvePreviousValid(int prolepticYear, int month, int day) {
......@@ -479,7 +479,7 @@ public final class HijrahDate
* @return the day-of-year
*/
private int getDayOfYear() {
return chrono.getDayOfYear(prolepticYear, monthOfYear);
return chrono.getDayOfYear(prolepticYear, monthOfYear) + dayOfMonth;
}
/**
......@@ -575,12 +575,13 @@ public final class HijrahDate
}
@Override // for javadoc and covariant return type
@SuppressWarnings("unchecked")
public final ChronoLocalDateTime<HijrahDate> atTime(LocalTime localTime) {
return super.atTime(localTime);
return (ChronoLocalDateTime<HijrahDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
public Period until(ChronoLocalDate endDate) {
// TODO: untested
HijrahDate end = getChronology().date(endDate);
long totalMonths = (end.prolepticYear - this.prolepticYear) * 12 + (end.monthOfYear - this.monthOfYear); // safe
......@@ -622,7 +623,7 @@ public final class HijrahDate
return this;
}
static ChronoLocalDate<HijrahDate> readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
HijrahChronology chrono = (HijrahChronology) in.readObject();
int year = in.readInt();
int month = in.readByte();
......
......@@ -61,25 +61,16 @@
*/
package java.time.chrono;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_WEEK;
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.EPOCH_DAY;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import static java.time.temporal.TemporalAdjuster.nextOrSame;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
......@@ -398,7 +389,7 @@ public final class IsoChronology extends Chronology implements Serializable {
}
@Override
public Era eraOf(int eraValue) {
public IsoEra eraOf(int eraValue) {
return IsoEra.of(eraValue);
}
......@@ -421,7 +412,7 @@ public final class IsoChronology extends Chronology implements Serializable {
* as follows.
* <ul>
* <li>{@code EPOCH_DAY} - If present, this is converted to a {@code LocalDate}
* all other date fields are then cross-checked against the date
* and all other date fields are then cross-checked against the date.
* <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the
* {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart
* then the field is validated.
......@@ -430,7 +421,7 @@ public final class IsoChronology extends Chronology implements Serializable {
* range is not validated, in smart and strict mode it is. The {@code ERA} is
* validated for range in all three modes. If only the {@code YEAR_OF_ERA} is
* present, and the mode is smart or lenient, then the current era (CE/AD)
* is assumed. In strict mode, no ers is assumed and the {@code YEAR_OF_ERA} is
* is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is
* left untouched. If only the {@code ERA} is present, then it is left untouched.
* <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} -
* If all three are present, then they are combined to form a {@code LocalDate}.
......@@ -495,48 +486,11 @@ public final class IsoChronology extends Chronology implements Serializable {
*/
@Override // override for performance
public LocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
// check epoch-day before inventing era
if (fieldValues.containsKey(EPOCH_DAY)) {
return LocalDate.ofEpochDay(fieldValues.remove(EPOCH_DAY));
}
// fix proleptic month before inventing era
resolveProlepticMonth(fieldValues, resolverStyle);
// invent era if necessary to resolve year-of-era
resolveYearOfEra(fieldValues, resolverStyle);
// build date
if (fieldValues.containsKey(YEAR)) {
if (fieldValues.containsKey(MONTH_OF_YEAR)) {
if (fieldValues.containsKey(DAY_OF_MONTH)) {
return resolveYMD(fieldValues, resolverStyle);
}
if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) {
if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) {
return resolveYMAA(fieldValues, resolverStyle);
}
if (fieldValues.containsKey(DAY_OF_WEEK)) {
return resolveYMAD(fieldValues, resolverStyle);
}
}
}
if (fieldValues.containsKey(DAY_OF_YEAR)) {
return resolveYD(fieldValues, resolverStyle);
}
if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) {
if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) {
return resolveYAA(fieldValues, resolverStyle);
}
if (fieldValues.containsKey(DAY_OF_WEEK)) {
return resolveYAD(fieldValues, resolverStyle);
}
}
}
return null;
return (LocalDate) super.resolveDate(fieldValues, resolverStyle);
}
private void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
@Override // override for better proleptic algorithm
void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
Long pMonth = fieldValues.remove(PROLEPTIC_MONTH);
if (pMonth != null) {
if (resolverStyle != ResolverStyle.LENIENT) {
......@@ -547,7 +501,8 @@ public final class IsoChronology extends Chronology implements Serializable {
}
}
private void resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
@Override // override for enhanced behaviour
LocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
Long yoeLong = fieldValues.remove(YEAR_OF_ERA);
if (yoeLong != null) {
if (resolverStyle != ResolverStyle.LENIENT) {
......@@ -575,10 +530,14 @@ public final class IsoChronology extends Chronology implements Serializable {
} else {
throw new DateTimeException("Invalid value for era: " + era);
}
} else if (fieldValues.containsKey(ERA)) {
ERA.checkValidValue(fieldValues.get(ERA)); // always validated
}
return null;
}
private LocalDate resolveYMD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
@Override // override for performance
LocalDate resolveYMD(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
......@@ -598,96 +557,6 @@ public final class IsoChronology extends Chronology implements Serializable {
return LocalDate.of(y, moy, dom);
}
private LocalDate resolveYD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
return LocalDate.of(y, 1, 1).plusDays(days);
}
int doy = DAY_OF_YEAR.checkValidIntValue(fieldValues.remove(DAY_OF_YEAR));
return LocalDate.ofYearDay(y, doy); // smart is same as strict
}
private LocalDate resolveYMAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1);
return LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks).plusDays(days);
}
int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH));
int ad = ALIGNED_DAY_OF_WEEK_IN_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH));
LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7 + (ad - 1));
if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) {
throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
}
return date;
}
private LocalDate resolveYMAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1);
long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
return resolveAligned(y, months, weeks, dow);
}
int moy = MONTH_OF_YEAR.checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR));
int aw = ALIGNED_WEEK_OF_MONTH.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH));
int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK));
LocalDate date = LocalDate.of(y, moy, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)));
if (resolverStyle == ResolverStyle.STRICT && date.getMonthValue() != moy) {
throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
}
return date;
}
private LocalDate resolveYAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1);
return LocalDate.of(y, 1, 1).plusWeeks(weeks).plusDays(days);
}
int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR));
int ad = ALIGNED_DAY_OF_WEEK_IN_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR));
LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7 + (ad - 1));
if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) {
throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
}
return date;
}
private LocalDate resolveYAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
int y = YEAR.checkValidIntValue(fieldValues.remove(YEAR));
if (resolverStyle == ResolverStyle.LENIENT) {
long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1);
long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1);
return resolveAligned(y, 0, weeks, dow);
}
int aw = ALIGNED_WEEK_OF_YEAR.checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR));
int dow = DAY_OF_WEEK.checkValidIntValue(fieldValues.remove(DAY_OF_WEEK));
LocalDate date = LocalDate.of(y, 1, 1).plusDays((aw - 1) * 7).with(nextOrSame(DayOfWeek.of(dow)));
if (resolverStyle == ResolverStyle.STRICT && date.getYear() != y) {
throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
}
return date;
}
private LocalDate resolveAligned(int y, long months, long weeks, long dow) {
LocalDate date = LocalDate.of(y, 1, 1).plusMonths(months).plusWeeks(weeks);
if (dow > 7) {
date = date.plusWeeks((dow - 1) / 7);
dow = ((dow - 1) % 7) + 1;
} else if (dow < 1) {
date = date.plusWeeks(Math.subtractExact(dow, 7) / 7);
dow = ((dow + 6) % 7) + 1;
}
return date.with(nextOrSame(DayOfWeek.of((int) dow)));
}
//-----------------------------------------------------------------------
@Override
public ValueRange range(ChronoField field) {
......
......@@ -56,6 +56,15 @@
*/
package java.time.chrono;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.ERA;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.MONTHS;
import java.io.Serializable;
import java.time.Clock;
import java.time.DateTimeException;
......@@ -63,13 +72,18 @@ import java.time.Instant;
import java.time.LocalDate;
import java.time.Year;
import java.time.ZoneId;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalField;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import sun.util.calendar.CalendarSystem;
import sun.util.calendar.LocalGregorianCalendar;
......@@ -82,8 +96,22 @@ import sun.util.calendar.LocalGregorianCalendar;
* The Japanese Imperial calendar system is the same as the ISO calendar system
* apart from the era-based year numbering.
* <p>
* Only Meiji (1865-04-07 - 1868-09-07) and later eras are supported.
* Older eras are handled as an unknown era where the year-of-era is the ISO year.
* Japan introduced the Gregorian calendar starting with Meiji 6.
* Only Meiji and later eras are supported;
* dates before Meiji 6, January 1 are not supported.
* <p>
* The supported {@code ChronoField} instances are:
* <ul>
* <li>{@code DAY_OF_WEEK}
* <li>{@code DAY_OF_MONTH}
* <li>{@code DAY_OF_YEAR}
* <li>{@code EPOCH_DAY}
* <li>{@code MONTH_OF_YEAR}
* <li>{@code PROLEPTIC_MONTH}
* <li>{@code YEAR_OF_ERA}
* <li>{@code YEAR}
* <li>{@code ERA}
* </ul>
*
* @implSpec
* This class is immutable and thread-safe.
......@@ -91,7 +119,6 @@ import sun.util.calendar.LocalGregorianCalendar;
* @since 1.8
*/
public final class JapaneseChronology extends Chronology implements Serializable {
// TODO: definition for unknown era may break requirement that year-of-era >= 1
static final LocalGregorianCalendar JCAL =
(LocalGregorianCalendar) CalendarSystem.forName("japanese");
......@@ -152,6 +179,16 @@ public final class JapaneseChronology extends Chronology implements Serializable
/**
* Obtains a local date in Japanese calendar system from the
* era, year-of-era, month-of-year and day-of-month fields.
* <p>
* The Japanese month and day-of-month are the same as those in the
* ISO calendar system. They are not reset when the era changes.
* For example:
* <pre>
* 6th Jan Showa 64 = ISO 1989-01-06
* 7th Jan Showa 64 = ISO 1989-01-07
* 8th Jan Heisei 1 = ISO 1989-01-08
* 9th Jan Heisei 1 = ISO 1989-01-09
* </pre>
*
* @param era the Japanese era, not null
* @param yearOfEra the year-of-era
......@@ -172,6 +209,9 @@ public final class JapaneseChronology extends Chronology implements Serializable
/**
* Obtains a local date in Japanese calendar system from the
* proleptic-year, month-of-year and day-of-month fields.
* <p>
* The Japanese proleptic year, month and day-of-month are the same as those
* in the ISO calendar system. They are not reset when the era changes.
*
* @param prolepticYear the proleptic-year
* @param month the month-of-year
......@@ -187,6 +227,17 @@ public final class JapaneseChronology extends Chronology implements Serializable
/**
* Obtains a local date in Japanese calendar system from the
* era, year-of-era and day-of-year fields.
* <p>
* The day-of-year in this factory is expressed relative to the start of the year-of-era.
* This definition changes the normal meaning of day-of-year only in those years
* where the year-of-era is reset to one due to a change in the era.
* For example:
* <pre>
* 6th Jan Showa 64 = day-of-year 6
* 7th Jan Showa 64 = day-of-year 7
* 8th Jan Heisei 1 = day-of-year 1
* 9th Jan Heisei 1 = day-of-year 2
* </pre>
*
* @param era the Japanese era, not null
* @param yearOfEra the year-of-era
......@@ -203,6 +254,10 @@ public final class JapaneseChronology extends Chronology implements Serializable
/**
* Obtains a local date in Japanese calendar system from the
* proleptic-year and day-of-year fields.
* <p>
* The day-of-year in this factory is expressed relative to the start of the proleptic year.
* The Japanese proleptic year and day-of-year are the same as those in the ISO calendar system.
* They are not reset when the era changes.
*
* @param prolepticYear the proleptic-year
* @param dayOfYear the day-of-year
......@@ -211,8 +266,7 @@ public final class JapaneseChronology extends Chronology implements Serializable
*/
@Override
public JapaneseDate dateYearDay(int prolepticYear, int dayOfYear) {
LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear);
return date(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
return new JapaneseDate(LocalDate.ofYearDay(prolepticYear, dayOfYear));
}
/**
......@@ -290,15 +344,6 @@ public final class JapaneseChronology extends Chronology implements Serializable
throw new ClassCastException("Era must be JapaneseEra");
}
if (era == JapaneseEra.SEIREKI) {
JapaneseEra nextEra = JapaneseEra.values()[1];
int nextEraYear = nextEra.getPrivateEra().getSinceDate().getYear();
if (yearOfEra >= nextEraYear || yearOfEra < Year.MIN_VALUE) {
throw new DateTimeException("Invalid yearOfEra value");
}
return yearOfEra;
}
JapaneseEra jera = (JapaneseEra) era;
int gregorianYear = jera.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
if (yearOfEra == 1) {
......@@ -320,14 +365,13 @@ public final class JapaneseChronology extends Chronology implements Serializable
* See the description of each Era for the numeric values of:
* {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
* {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
* Prior to Meiji {@link JapaneseEra#SEIREKI} is used.
*
* @param eraValue the era value
* @return the Japanese {@code Era} for the given numeric era value
* @throws DateTimeException if {@code eraValue} is invalid
*/
@Override
public Era eraOf(int eraValue) {
public JapaneseEra eraOf(int eraValue) {
return JapaneseEra.of(eraValue);
}
......@@ -346,49 +390,117 @@ public final class JapaneseChronology extends Chronology implements Serializable
@Override
public ValueRange range(ChronoField field) {
switch (field) {
case YEAR:
case DAY_OF_MONTH:
case DAY_OF_WEEK:
case MICRO_OF_DAY:
case MICRO_OF_SECOND:
case HOUR_OF_DAY:
case HOUR_OF_AMPM:
case MINUTE_OF_DAY:
case MINUTE_OF_HOUR:
case SECOND_OF_DAY:
case SECOND_OF_MINUTE:
case MILLI_OF_DAY:
case MILLI_OF_SECOND:
case NANO_OF_DAY:
case NANO_OF_SECOND:
case CLOCK_HOUR_OF_DAY:
case CLOCK_HOUR_OF_AMPM:
case EPOCH_DAY:
case PROLEPTIC_MONTH:
case MONTH_OF_YEAR:
return field.range();
case ERA:
return ValueRange.of(JapaneseEra.SEIREKI.getValue(),
getCurrentEra().getValue());
}
Calendar jcal = Calendar.getInstance(LOCALE);
int fieldIndex;
switch (field) {
case ALIGNED_DAY_OF_WEEK_IN_MONTH:
case ALIGNED_DAY_OF_WEEK_IN_YEAR:
case ALIGNED_WEEK_OF_MONTH:
case ALIGNED_WEEK_OF_YEAR:
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
case YEAR_OF_ERA: {
Calendar jcal = Calendar.getInstance(LOCALE);
int startYear = getCurrentEra().getPrivateEra().getSinceDate().getYear();
return ValueRange.of(Year.MIN_VALUE, jcal.getGreatestMinimum(Calendar.YEAR),
return ValueRange.of(1, jcal.getGreatestMinimum(Calendar.YEAR),
jcal.getLeastMaximum(Calendar.YEAR) + 1, // +1 due to the different definitions
Year.MAX_VALUE - startYear);
}
case DAY_OF_YEAR:
fieldIndex = Calendar.DAY_OF_YEAR;
break;
case DAY_OF_YEAR: {
Calendar jcal = Calendar.getInstance(LOCALE);
int fieldIndex = Calendar.DAY_OF_YEAR;
return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
}
case YEAR:
return ValueRange.of(JapaneseDate.MEIJI_6_ISODATE.getYear(), Year.MAX_VALUE);
case ERA:
return ValueRange.of(JapaneseEra.MEIJI.getValue(), getCurrentEra().getValue());
default:
// TODO: review the remaining fields
throw new UnsupportedOperationException("Unimplementable field: " + field);
return field.range();
}
}
//-----------------------------------------------------------------------
@Override // override for return type
public JapaneseDate resolveDate(Map <TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
return (JapaneseDate) super.resolveDate(fieldValues, resolverStyle);
}
@Override // override for special Japanese behavior
ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
// validate era and year-of-era
Long eraLong = fieldValues.get(ERA);
JapaneseEra era = null;
if (eraLong != null) {
era = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); // always validated
}
Long yoeLong = fieldValues.get(YEAR_OF_ERA);
int yoe = 0;
if (yoeLong != null) {
yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); // always validated
}
// if only year-of-era and no year then invent era unless strict
if (era == null && yoeLong != null && fieldValues.containsKey(YEAR) == false && resolverStyle != ResolverStyle.STRICT) {
era = JapaneseEra.values()[JapaneseEra.values().length - 1];
}
// if both present, then try to create date
if (yoeLong != null && era != null) {
if (fieldValues.containsKey(MONTH_OF_YEAR)) {
if (fieldValues.containsKey(DAY_OF_MONTH)) {
return resolveYMD(era, yoe, fieldValues, resolverStyle);
}
}
if (fieldValues.containsKey(DAY_OF_YEAR)) {
return resolveYD(era, yoe, fieldValues, resolverStyle);
}
}
return null;
}
private int prolepticYearLenient(JapaneseEra era, int yearOfEra) {
return era.getPrivateEra().getSinceDate().getYear() + yearOfEra - 1;
}
private ChronoLocalDate resolveYMD(JapaneseEra era, int yoe, Map<TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
fieldValues.remove(ERA);
fieldValues.remove(YEAR_OF_ERA);
if (resolverStyle == ResolverStyle.LENIENT) {
int y = prolepticYearLenient(era, yoe);
long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1);
long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1);
return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS);
}
int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR);
int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH);
if (resolverStyle == ResolverStyle.SMART) { // previous valid
if (yoe < 1) {
throw new DateTimeException("Invalid YearOfEra: " + yoe);
}
int y = prolepticYearLenient(era, yoe);
JapaneseDate result;
try {
result = date(y, moy, dom);
} catch (DateTimeException ex) {
result = date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth());
}
// handle the era being changed
// only allow if the new date is in the same Jan-Dec as the era change
// determine by ensuring either original yoe or result yoe is 1
if (result.getEra() != era && result.get(YEAR_OF_ERA) > 1 && yoe > 1) {
throw new DateTimeException("Invalid YearOfEra for Era: " + era + " " + yoe);
}
return result;
}
return date(era, yoe, moy, dom);
}
private ChronoLocalDate resolveYD(JapaneseEra era, int yoe, Map <TemporalField,Long> fieldValues, ResolverStyle resolverStyle) {
fieldValues.remove(ERA);
fieldValues.remove(YEAR_OF_ERA);
if (resolverStyle == ResolverStyle.LENIENT) {
int y = prolepticYearLenient(era, yoe);
long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1);
return dateYearDay(y, 1).plus(days, DAYS);
}
return ValueRange.of(jcal.getMinimum(fieldIndex), jcal.getGreatestMinimum(fieldIndex),
jcal.getLeastMaximum(fieldIndex), jcal.getMaximum(fieldIndex));
int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR);
return dateYearDay(era, yoe, doy); // smart is same as strict
}
}
......@@ -56,9 +56,15 @@
*/
package java.time.chrono;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH;
import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.DAY_OF_YEAR;
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
import static java.time.temporal.ChronoField.YEAR;
import static java.time.temporal.ChronoField.YEAR_OF_ERA;
import java.io.DataInput;
import java.io.DataOutput;
......@@ -96,6 +102,10 @@ import sun.util.calendar.LocalGregorianCalendar;
* apart from the era-based year numbering. The proleptic-year is defined to be
* equal to the ISO proleptic-year.
* <p>
* Japan introduced the Gregorian calendar starting with Meiji 6.
* Only Meiji and later eras are supported;
* dates before Meiji 6, January 1 are not supported.
* <p>
* For example, the Japanese year "Heisei 24" corresponds to ISO year "2012".<br>
* Calling {@code japaneseDate.get(YEAR_OF_ERA)} will return 24.<br>
* Calling {@code japaneseDate.get(YEAR)} will return 2012.<br>
......@@ -109,7 +119,7 @@ import sun.util.calendar.LocalGregorianCalendar;
*/
public final class JapaneseDate
extends ChronoDateImpl<JapaneseDate>
implements ChronoLocalDate<JapaneseDate>, Serializable {
implements ChronoLocalDate, Serializable {
/**
* Serialization version.
......@@ -129,6 +139,11 @@ public final class JapaneseDate
*/
private transient int yearOfEra;
/**
* The first day supported by the JapaneseChronology is Meiji 6, January 1st.
*/
final static LocalDate MEIJI_6_ISODATE = LocalDate.of(1873, 1, 1);
//-----------------------------------------------------------------------
/**
* Obtains the current {@code JapaneseDate} from the system clock in the default time-zone.
......@@ -173,7 +188,7 @@ public final class JapaneseDate
* @throws DateTimeException if the current date cannot be obtained
*/
public static JapaneseDate now(Clock clock) {
return JapaneseChronology.INSTANCE.date(LocalDate.now(clock));
return new JapaneseDate(LocalDate.now(clock));
}
/**
......@@ -182,6 +197,16 @@ public final class JapaneseDate
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
* <p>
* The Japanese month and day-of-month are the same as those in the
* ISO calendar system. They are not reset when the era changes.
* For example:
* <pre>
* 6th Jan Showa 64 = ISO 1989-01-06
* 7th Jan Showa 64 = ISO 1989-01-07
* 8th Jan Heisei 1 = ISO 1989-01-08
* 9th Jan Heisei 1 = ISO 1989-01-09
* </pre>
*
* @param era the Japanese era, not null
* @param yearOfEra the Japanese year-of-era
......@@ -192,11 +217,15 @@ public final class JapaneseDate
* or if the day-of-month is invalid for the month-year,
* or if the date is not a Japanese era
*/
public static JapaneseDate of(Era era, int yearOfEra, int month, int dayOfMonth) {
if (era instanceof JapaneseEra == false) {
throw new ClassCastException("Era must be JapaneseEra");
public static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
Objects.requireNonNull(era, "era");
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
if (!JapaneseChronology.JCAL.validate(jdate)) {
throw new DateTimeException("year, month, and day not valid for Era");
}
return JapaneseDate.of((JapaneseEra) era, yearOfEra, month, dayOfMonth);
LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
return new JapaneseDate(era, yearOfEra, date);
}
/**
......@@ -205,6 +234,9 @@ public final class JapaneseDate
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
* <p>
* The Japanese proleptic year, month and day-of-month are the same as those
* in the ISO calendar system. They are not reset when the era changes.
*
* @param prolepticYear the Japanese proleptic-year
* @param month the Japanese month-of-year, from 1 to 12
......@@ -219,23 +251,31 @@ public final class JapaneseDate
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the proleptic-year and day-of-year fields.
* system from the era, year-of-era and day-of-year fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year, otherwise an exception will be thrown.
* <p>
* The day-of-year in this factory is expressed relative to the start of the year-of-era.
* This definition changes the normal meaning of day-of-year only in those years
* where the year-of-era is reset to one due to a change in the era.
* For example:
* <pre>
* 6th Jan Showa 64 = day-of-year 6
* 7th Jan Showa 64 = day-of-year 7
* 8th Jan Heisei 1 = day-of-year 1
* 9th Jan Heisei 1 = day-of-year 2
* </pre>
*
* @param prolepticYear the chronology proleptic-year
* @param era the Japanese era, not null
* @param yearOfEra the Japanese year-of-era
* @param dayOfYear the chronology day-of-year, from 1 to 366
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-year is invalid for the year
*/
public static JapaneseDate ofYearDay(int prolepticYear, int dayOfYear) {
LocalDate date = LocalDate.ofYearDay(prolepticYear, dayOfYear);
return of(prolepticYear, date.getMonthValue(), date.getDayOfMonth());
}
static JapaneseDate ofYearDay(JapaneseEra era, int yearOfEra, int dayOfYear) {
Objects.requireNonNull(era, "era");
CalendarDate firstDay = era.getPrivateEra().getSinceDate();
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
jdate.setEra(era.getPrivateEra());
......@@ -253,32 +293,6 @@ public final class JapaneseDate
return new JapaneseDate(era, yearOfEra, localdate);
}
/**
* Obtains a {@code JapaneseDate} representing a date in the Japanese calendar
* system from the era, year-of-era, month-of-year and day-of-month fields.
* <p>
* This returns a {@code JapaneseDate} with the specified fields.
* The day must be valid for the year and month, otherwise an exception will be thrown.
*
* @param era the Japanese era, not null
* @param yearOfEra the Japanese year-of-era
* @param month the Japanese month-of-year, from 1 to 12
* @param dayOfMonth the Japanese day-of-month, from 1 to 31
* @return the date in Japanese calendar system, not null
* @throws DateTimeException if the value of any field is out of range,
* or if the day-of-month is invalid for the month-year
*/
static JapaneseDate of(JapaneseEra era, int yearOfEra, int month, int dayOfMonth) {
Objects.requireNonNull(era, "era");
LocalGregorianCalendar.Date jdate = JapaneseChronology.JCAL.newCalendarDate(null);
jdate.setEra(era.getPrivateEra()).setDate(yearOfEra, month, dayOfMonth);
if (!JapaneseChronology.JCAL.validate(jdate)) {
throw new DateTimeException("year, month, and day not valid for Era");
}
LocalDate date = LocalDate.of(jdate.getNormalizedYear(), month, dayOfMonth);
return new JapaneseDate(era, yearOfEra, date);
}
/**
* Obtains a {@code JapaneseDate} from a temporal object.
* <p>
......@@ -307,6 +321,9 @@ public final class JapaneseDate
* @param isoDate the standard local date, validated not null
*/
JapaneseDate(LocalDate isoDate) {
if (isoDate.isBefore(MEIJI_6_ISODATE)) {
throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
}
LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
this.era = JapaneseEra.toJapaneseEra(jdate.getEra());
this.yearOfEra = jdate.getYear();
......@@ -322,6 +339,9 @@ public final class JapaneseDate
* @param isoDate the standard local date, validated not null
*/
JapaneseDate(JapaneseEra era, int year, LocalDate isoDate) {
if (isoDate.isBefore(MEIJI_6_ISODATE)) {
throw new DateTimeException("JapaneseDate before Meiji 6 is not supported");
}
this.era = era;
this.yearOfEra = year;
this.isoDate = isoDate;
......@@ -366,55 +386,99 @@ public final class JapaneseDate
return isoDate.lengthOfMonth();
}
@Override
public int lengthOfYear() {
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
return jcal.getActualMaximum(Calendar.DAY_OF_YEAR);
}
//-----------------------------------------------------------------------
/**
* Checks if the specified field is supported.
* <p>
* This checks if this date can be queried for the specified field.
* If false, then calling the {@link #range(TemporalField) range} and
* {@link #get(TemporalField) get} methods will throw an exception.
* <p>
* If the field is a {@link ChronoField} then the query is implemented here.
* The supported fields are:
* <ul>
* <li>{@code DAY_OF_WEEK}
* <li>{@code DAY_OF_MONTH}
* <li>{@code DAY_OF_YEAR}
* <li>{@code EPOCH_DAY}
* <li>{@code MONTH_OF_YEAR}
* <li>{@code PROLEPTIC_MONTH}
* <li>{@code YEAR_OF_ERA}
* <li>{@code YEAR}
* <li>{@code ERA}
* </ul>
* All other {@code ChronoField} instances will return false.
* <p>
* If the field is not a {@code ChronoField}, then the result of this method
* is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
* passing {@code this} as the argument.
* Whether the field is supported is determined by the field.
*
* @param field the field to check, null returns false
* @return true if the field is supported on this date, false if not
*/
@Override
public boolean isSupported(TemporalField field) {
if (field == ALIGNED_DAY_OF_WEEK_IN_MONTH || field == ALIGNED_DAY_OF_WEEK_IN_YEAR ||
field == ALIGNED_WEEK_OF_MONTH || field == ALIGNED_WEEK_OF_YEAR) {
return false;
}
return ChronoLocalDate.super.isSupported(field);
}
@Override
public ValueRange range(TemporalField field) {
if (field instanceof ChronoField) {
if (isSupported(field)) {
ChronoField f = (ChronoField) field;
switch (f) {
case DAY_OF_MONTH:
case ALIGNED_WEEK_OF_MONTH:
return isoDate.range(field);
case DAY_OF_YEAR:
return actualRange(Calendar.DAY_OF_YEAR);
case YEAR_OF_ERA:
return actualRange(Calendar.YEAR);
case DAY_OF_MONTH: return ValueRange.of(1, lengthOfMonth());
case DAY_OF_YEAR: return ValueRange.of(1, lengthOfYear());
case YEAR_OF_ERA: {
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
return ValueRange.of(1, jcal.getActualMaximum(Calendar.YEAR));
}
}
return getChronology().range(f);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.rangeRefinedBy(this);
}
private ValueRange actualRange(int calendarField) {
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET); // TODO: cannot calculate this way for SEIREKI
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
return ValueRange.of(jcal.getActualMinimum(calendarField),
jcal.getActualMaximum(calendarField));
}
@Override
public long getLong(TemporalField field) {
if (field instanceof ChronoField) {
// same as ISO:
// DAY_OF_WEEK, ALIGNED_DAY_OF_WEEK_IN_MONTH, DAY_OF_MONTH, EPOCH_DAY,
// ALIGNED_WEEK_OF_MONTH, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
// DAY_OF_WEEK, DAY_OF_MONTH, EPOCH_DAY, MONTH_OF_YEAR, PROLEPTIC_MONTH, YEAR
//
// calendar specific fields
// ALIGNED_DAY_OF_WEEK_IN_YEAR, DAY_OF_YEAR, ALIGNED_WEEK_OF_YEAR, YEAR_OF_ERA, ERA
// DAY_OF_YEAR, YEAR_OF_ERA, ERA
switch ((ChronoField) field) {
case ALIGNED_DAY_OF_WEEK_IN_MONTH:
case ALIGNED_DAY_OF_WEEK_IN_YEAR:
case ALIGNED_WEEK_OF_MONTH:
case ALIGNED_WEEK_OF_YEAR:
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
case YEAR_OF_ERA:
return yearOfEra;
case ERA:
return era.getValue();
case DAY_OF_YEAR: {
LocalGregorianCalendar.Date jdate = toPrivateJapaneseDate(isoDate);
return JapaneseChronology.JCAL.getDayOfYear(jdate);
}
// TODO: ALIGNED_DAY_OF_WEEK_IN_YEAR and ALIGNED_WEEK_OF_YEAR ???
case DAY_OF_YEAR:
Calendar jcal = Calendar.getInstance(JapaneseChronology.LOCALE);
jcal.set(Calendar.ERA, era.getValue() + JapaneseEra.ERA_OFFSET);
jcal.set(yearOfEra, isoDate.getMonthValue() - 1, isoDate.getDayOfMonth());
return jcal.get(Calendar.DAY_OF_YEAR);
}
return isoDate.getLong(field);
}
......@@ -444,7 +508,7 @@ public final class JapaneseDate
public JapaneseDate with(TemporalField field, long newValue) {
if (field instanceof ChronoField) {
ChronoField f = (ChronoField) field;
if (getLong(f) == newValue) {
if (getLong(f) == newValue) { // getLong() validates for supported fields
return this;
}
switch (f) {
......@@ -464,10 +528,9 @@ public final class JapaneseDate
}
}
// YEAR, PROLEPTIC_MONTH and others are same as ISO
// TODO: review other fields, such as WEEK_OF_YEAR
return with(isoDate.with(field, newValue));
}
return ChronoLocalDate.super.with(field, newValue);
return super.with(field, newValue);
}
/**
......@@ -592,13 +655,14 @@ public final class JapaneseDate
}
@Override // for javadoc and covariant return type
@SuppressWarnings("unchecked")
public final ChronoLocalDateTime<JapaneseDate> atTime(LocalTime localTime) {
return super.atTime(localTime);
return (ChronoLocalDateTime<JapaneseDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
return isoDate.periodUntil(endDate);
public Period until(ChronoLocalDate endDate) {
return isoDate.until(endDate);
}
@Override // override for performance
......@@ -624,14 +688,6 @@ public final class JapaneseDate
return getChronology().getId().hashCode() ^ isoDate.hashCode();
}
@Override
public String toString() {
if (era == JapaneseEra.SEIREKI) {
return getChronology().getId() + " " + isoDate.toString();
}
return super.toString();
}
//-----------------------------------------------------------------------
private Object writeReplace() {
return new Ser(Ser.JAPANESE_DATE_TYPE, this);
......
......@@ -61,6 +61,7 @@
*/
package java.time.chrono;
import static java.time.chrono.JapaneseDate.MEIJI_6_ISODATE;
import static java.time.temporal.ChronoField.ERA;
import java.io.DataInput;
......@@ -84,12 +85,9 @@ import sun.util.calendar.CalendarDate;
* An era in the Japanese Imperial calendar system.
* <p>
* This class defines the valid eras for the Japanese chronology.
* Only Meiji (1868-09-08 - 1912-07-29) and later eras are supported.
* Japan introduced the Gregorian calendar since Meiji 6. The dates
* between Meiji 1 - 5 are not historically correct.
* The older eras are recognized as Seireki (Western calendar) era,
* and the year of era of Seireki is proleptic Gregorian year.
* (The Julian to Gregorian transition is not supported.)
* Japan introduced the Gregorian calendar starting with Meiji 6.
* Only Meiji and later eras are supported;
* dates before Meiji 6, January 1 are not supported.
*
* @implSpec
* This class is immutable and thread-safe.
......@@ -100,16 +98,11 @@ public final class JapaneseEra
implements Era, Serializable {
// The offset value to 0-based index from the era value.
// i.e., getValue() + ERA_OFFSET == 0-based index; except that -999 is mapped to zero
// i.e., getValue() + ERA_OFFSET == 0-based index
static final int ERA_OFFSET = 2;
static final sun.util.calendar.Era[] ERA_CONFIG;
/**
* The singleton instance for the before Meiji era ( - 1868-09-07)
* which has the value -999.
*/
public static final JapaneseEra SEIREKI = new JapaneseEra(-999, LocalDate.MIN);
/**
* The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29)
* which has the value -1.
......@@ -144,17 +137,13 @@ public final class JapaneseEra
private static final JapaneseEra[] KNOWN_ERAS;
static {
sun.util.calendar.Era[] sunEras = JapaneseChronology.JCAL.getEras();
ERA_CONFIG = new sun.util.calendar.Era[sunEras.length + 1];
for (int i = 1; i < ERA_CONFIG.length; i++) {
ERA_CONFIG[i] = sunEras[i - 1];
}
ERA_CONFIG = JapaneseChronology.JCAL.getEras();
KNOWN_ERAS = new JapaneseEra[ERA_CONFIG.length];
KNOWN_ERAS[0] = SEIREKI;
KNOWN_ERAS[1] = MEIJI;
KNOWN_ERAS[2] = TAISHO;
KNOWN_ERAS[3] = SHOWA;
KNOWN_ERAS[4] = HEISEI;
KNOWN_ERAS[0] = MEIJI;
KNOWN_ERAS[1] = TAISHO;
KNOWN_ERAS[2] = SHOWA;
KNOWN_ERAS[3] = HEISEI;
for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
CalendarDate date = ERA_CONFIG[i].getSinceDate();
LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
......@@ -203,10 +192,8 @@ public final class JapaneseEra
//-----------------------------------------------------------------------
/**
* Returns the Sun private Era instance corresponding to this {@code JapaneseEra}.
* SEIREKI doesn't have its corresponding one.
*
* @return the Sun private Era instance for this {@code JapaneseEra},
* or null for SEIREKI.
* @return the Sun private Era instance for this {@code JapaneseEra}.
*/
sun.util.calendar.Era getPrivateEra() {
return ERA_CONFIG[ordinal(eraValue)];
......@@ -218,16 +205,14 @@ public final class JapaneseEra
* <p>
* The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1
* Later era is numbered 2 ({@link #HEISEI}). Earlier eras are numbered 0 ({@link #TAISHO}),
* -1 ({@link #MEIJI}), only Meiji and later eras are supported. The prior to Meiji,
* {@link #SEIREKI} is used.
* -1 ({@link #MEIJI}), only Meiji and later eras are supported.
*
* @param japaneseEra the era to represent
* @return the {@code JapaneseEra} singleton, not null
* @throws DateTimeException if the value is invalid
*/
public static JapaneseEra of(int japaneseEra) {
if (japaneseEra != SEIREKI.eraValue &&
(japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue)) {
if (japaneseEra < MEIJI.eraValue || japaneseEra > HEISEI.eraValue) {
throw new DateTimeException("Invalid era: " + japaneseEra);
}
return KNOWN_ERAS[ordinal(japaneseEra)];
......@@ -276,22 +261,25 @@ public final class JapaneseEra
* @return the Era singleton, never null
*/
static JapaneseEra from(LocalDate date) {
if (date.isBefore(MEIJI_6_ISODATE)) {
throw new DateTimeException("JapaneseDate before Meiji 6 are not supported");
}
for (int i = KNOWN_ERAS.length - 1; i > 0; i--) {
JapaneseEra era = KNOWN_ERAS[i];
if (date.compareTo(era.since) >= 0) {
return era;
}
}
return SEIREKI;
return null;
}
static JapaneseEra toJapaneseEra(sun.util.calendar.Era privateEra) {
for (int i = ERA_CONFIG.length - 1; i > 0; i--) {
for (int i = ERA_CONFIG.length - 1; i >= 0; i--) {
if (ERA_CONFIG[i].equals(privateEra)) {
return KNOWN_ERAS[i];
}
}
return SEIREKI;
return null;
}
static sun.util.calendar.Era privateEraFrom(LocalDate isoDate) {
......@@ -306,13 +294,13 @@ public final class JapaneseEra
/**
* Returns the index into the arrays from the Era value.
* the eraValue is a valid Era number, -999, -1..2.
* the eraValue is a valid Era number, -1..2.
*
* @param eraValue the era value to convert to the index
* @return the index of the current Era
*/
private static int ordinal(int eraValue) {
return (eraValue == SEIREKI.eraValue) ? 0 : eraValue + ERA_OFFSET;
return eraValue + ERA_OFFSET - 1;
}
//-----------------------------------------------------------------------
......@@ -321,7 +309,7 @@ public final class JapaneseEra
* <p>
* The {@link #SHOWA} era that contains 1970-01-01 (ISO calendar system) has the value 1.
* Later eras are numbered from 2 ({@link #HEISEI}).
* Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI}), and -999 ({@link #SEIREKI}).
* Earlier eras are numbered 0 ({@link #TAISHO}), -1 ({@link #MEIJI})).
*
* @return the era value
*/
......@@ -374,11 +362,7 @@ public final class JapaneseEra
}
String getName() {
int index = ordinal(getValue());
if (index == 0) {
return "Seireki";
}
return ERA_CONFIG[index].getName();
return ERA_CONFIG[ordinal(getValue())].getName();
}
@Override
......
......@@ -65,12 +65,15 @@ import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* The Minguo calendar system.
......@@ -253,16 +256,19 @@ public final class MinguoChronology extends Chronology implements Serializable {
}
@Override
@SuppressWarnings("unchecked")
public ChronoLocalDateTime<MinguoDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<MinguoDate>)super.localDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<MinguoDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<MinguoDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<MinguoDate>)super.zonedDateTime(instant, zone);
}
......@@ -292,7 +298,7 @@ public final class MinguoChronology extends Chronology implements Serializable {
}
@Override
public Era eraOf(int eraValue) {
public MinguoEra eraOf(int eraValue) {
return MinguoEra.of(eraValue);
}
......@@ -321,4 +327,10 @@ public final class MinguoChronology extends Chronology implements Serializable {
return field.range();
}
//-----------------------------------------------------------------------
@Override // override for return type
public MinguoDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
return (MinguoDate) super.resolveDate(fieldValues, resolverStyle);
}
}
......@@ -96,7 +96,7 @@ import java.util.Objects;
*/
public final class MinguoDate
extends ChronoDateImpl<MinguoDate>
implements ChronoLocalDate<MinguoDate>, Serializable {
implements ChronoLocalDate, Serializable {
/**
* Serialization version.
......@@ -152,7 +152,7 @@ public final class MinguoDate
* @throws DateTimeException if the current date cannot be obtained
*/
public static MinguoDate now(Clock clock) {
return MinguoChronology.INSTANCE.date(LocalDate.now(clock));
return new MinguoDate(LocalDate.now(clock));
}
/**
......@@ -264,7 +264,7 @@ public final class MinguoDate
}
return getChronology().range(f);
}
throw new UnsupportedTemporalTypeException("Unsupported field: " + field.getName());
throw new UnsupportedTemporalTypeException("Unsupported field: " + field);
}
return field.rangeRefinedBy(this);
}
......@@ -325,7 +325,7 @@ public final class MinguoDate
}
return with(isoDate.with(field, newValue));
}
return ChronoLocalDate.super.with(field, newValue);
return super.with(field, newValue);
}
/**
......@@ -369,6 +369,11 @@ public final class MinguoDate
return with(isoDate.plusMonths(months));
}
@Override
MinguoDate plusWeeks(long weeksToAdd) {
return super.plusWeeks(weeksToAdd);
}
@Override
MinguoDate plusDays(long days) {
return with(isoDate.plusDays(days));
......@@ -384,11 +389,6 @@ public final class MinguoDate
return super.minus(amountToAdd, unit);
}
@Override
MinguoDate plusWeeks(long weeksToAdd) {
return super.plusWeeks(weeksToAdd);
}
@Override
MinguoDate minusYears(long yearsToSubtract) {
return super.minusYears(yearsToSubtract);
......@@ -414,13 +414,14 @@ public final class MinguoDate
}
@Override // for javadoc and covariant return type
@SuppressWarnings("unchecked")
public final ChronoLocalDateTime<MinguoDate> atTime(LocalTime localTime) {
return super.atTime(localTime);
return (ChronoLocalDateTime<MinguoDate>)super.atTime(localTime);
}
@Override
public Period periodUntil(ChronoLocalDate<?> endDate) {
return isoDate.periodUntil(endDate);
public Period until(ChronoLocalDate endDate) {
return isoDate.until(endDate);
}
@Override // override for performance
......@@ -458,7 +459,7 @@ public final class MinguoDate
out.writeByte(get(DAY_OF_MONTH));
}
static ChronoLocalDate<?> readExternal(DataInput in) throws IOException {
static MinguoDate readExternal(DataInput in) throws IOException {
int year = in.readInt();
int month = in.readByte();
int dayOfMonth = in.readByte();
......
......@@ -65,13 +65,16 @@ import java.time.DateTimeException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.ResolverStyle;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
import java.time.temporal.ValueRange;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
/**
* The Thai Buddhist calendar system.
......@@ -289,16 +292,19 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ
}
@Override
@SuppressWarnings("unchecked")
public ChronoLocalDateTime<ThaiBuddhistDate> localDateTime(TemporalAccessor temporal) {
return (ChronoLocalDateTime<ThaiBuddhistDate>)super.localDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(TemporalAccessor temporal) {
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(temporal);
}
@Override
@SuppressWarnings("unchecked")
public ChronoZonedDateTime<ThaiBuddhistDate> zonedDateTime(Instant instant, ZoneId zone) {
return (ChronoZonedDateTime<ThaiBuddhistDate>)super.zonedDateTime(instant, zone);
}
......@@ -328,7 +334,7 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ
}
@Override
public Era eraOf(int eraValue) {
public ThaiBuddhistEra eraOf(int eraValue) {
return ThaiBuddhistEra.of(eraValue);
}
......@@ -357,4 +363,10 @@ public final class ThaiBuddhistChronology extends Chronology implements Serializ
return field.range();
}
//-----------------------------------------------------------------------
@Override // override for return type
public ThaiBuddhistDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) {
return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle);
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册