📄 datetimeattribute.java
字号:
/*
* @(#)DateTimeAttribute.java
*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/
package com.sun.xacml.attr;
import com.sun.xacml.ParsingException;
import java.net.URI;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import org.w3c.dom.Node;
/**
* Representation of an xs:dateTime value. This class supports parsing
* xs:dateTime values. All objects of this class are immutable and
* thread-safe. The <code>Date</code> objects returned are not, but
* these objects are cloned before being returned.
*
* @since 1.0
* @author Marco Barreno
* @author Seth Proctor
* @author Steve Hanna
*/
public class DateTimeAttribute extends AttributeValue
{
/**
* Official name of this type
*/
public static final String identifier =
"http://www.w3.org/2001/XMLSchema#dateTime";
/**
* URI version of name for this type
* <p>
* This field is initialized by a static initializer so that
* we can catch any exceptions thrown by URI(String) and
* transform them into a RuntimeException, since this should
* never happen but should be reported properly if it ever does.
* <p>
* This object is used for synchronization whenever we need
* protection across this whole class.
*/
private static URI identifierURI;
/**
* RuntimeException that wraps an Exception thrown during the
* creation of identifierURI, null if none.
*/
private static RuntimeException earlyException;
/**
* Static initializer that initializes the identifierURI
* class field so that we can catch any exceptions thrown
* by URI(String) and transform them into a RuntimeException.
* Such exceptions should never happen but should be reported
* properly if they ever do.
*/
static {
try {
identifierURI = new URI(identifier);
} catch (Exception e) {
earlyException = new IllegalArgumentException();
earlyException.initCause(e);
}
};
/**
* Parser for dates with no time zones
* <p>
* This field is only initialized if needed (by initParsers()).
* <p>
* NOTE: This object should only be accessed from code that
* has synchronized on it, since SimpleDateFormat objects are not
* thread-safe. If this is causing performance problems, we could
* easily make this a method variable in methods that use it
* instead of a class field. But that would mean we'd need to
* spend a lot more time creating these objects.
*/
private static DateFormat simpleParser;
/**
* Parser for dates with RFC 822 time zones (like +0300)
* <p>
* This field is only initialized if needed (by initParsers()).
* <p>
* NOTE: This object should only be accessed from code that
* has synchronized on it, since SimpleDateFormat objects are not
* thread-safe.
*/
private static DateFormat zoneParser;
/**
* Calendar for GMT
* <p>
* NOTE: This object should only be accessed from code that
* has a lock on it, since Calendar objects are not generally
* thread-safe.
*/
private static Calendar gmtCalendar;
/**
* Time zone value that indicates that the time zone was not
* specified.
*/
public static final int TZ_UNSPECIFIED = -1000000;
/**
* The actual date and time that this object represents (in GMT,
* as with all Date objects). If no time zone was specified, the
* local time zone is used to convert to GMT.
* <p>
* This Date does not include fractions of a second. Those are
* handled by the separate nanoseconds field, since Date only
* provides millisecond accuracy and the XML Query spec requires
* at least 100 nanosecond accuracy.
*/
private Date value;
/**
* The number of nanoseconds beyond the Date given by the value
* field. The XML Query document says that fractional seconds
* must be supported down to at least 100 nanosecond resolution.
* The Date class only supports milliseconds, so we include here
* support for nanosecond resolution.
*/
private int nanoseconds;
/**
* The time zone specified for this object (or TZ_UNSPECIFIED if
* unspecified). The offset to GMT, in minutes.
*/
private int timeZone;
/**
* The time zone actually used for this object (if it was
* originally unspecified, the default time zone used).
* The offset to GMT, in minutes.
*/
private int defaultedTimeZone;
/**
* Cached encoded value (null if not cached yet).
*/
private String encodedValue = null;
/**
* Creates a new <code>DateTimeAttribute</code> that represents
* the current date in the default time zone.
*/
public DateTimeAttribute() {
this(new Date());
}
/**
* Creates a new <code>DateTimeAttribute</code> that represents
* the supplied date but uses default timezone and offset values.
*
* @param dateTime a <code>Date</code> object representing the
* specified date and time down to second
* resolution. If this object has non-zero
* milliseconds, they are combined
* with the nanoseconds parameter.
*/
public DateTimeAttribute(Date dateTime) {
super(identifierURI);
int currOffset = getDefaultTZOffset(dateTime);
init(dateTime, 0, currOffset, currOffset);
}
/**
* Creates a new <code>DateTimeAttribute</code> that represents
* the date supplied.
*
* @param dateTime a <code>Date</code> object representing the
* specified date and time down to second
* resolution. If this object has non-zero
* milliseconds, they are combined
* with the nanoseconds parameter.
* @param nanoseconds the number of nanoseconds beyond the
* Date specified in the date parameter
* @param timeZone the time zone specified for this object
* (or TZ_UNSPECIFIED if unspecified). The
* offset to GMT, in minutes.
* @param defaultedTimeZone the time zone actually used for this
* object (if it was originally unspecified,
* the default time zone used).
* The offset to GMT, in minutes.
*/
public DateTimeAttribute(Date dateTime, int nanoseconds, int timeZone,
int defaultedTimeZone) {
super(identifierURI);
init(dateTime, nanoseconds, timeZone, defaultedTimeZone);
}
/**
* Initialization code shared by constructors.
*
* @param date a <code>Date</code> object representing the
* specified date and time down to second
* resolution. If this object has non-zero
* milliseconds, they are combined
* with the nanoseconds parameter.
* @param nanoseconds the number of nanoseconds beyond the
* Date specified in the date parameter
* @param timeZone the time zone specified for this object
* (or TZ_UNSPECIFIED if unspecified). The
* offset to GMT, in minutes.
* @param defaultedTimeZone the time zone actually used for this
* object (if it was originally unspecified,
* the default time zone used).
* The offset to GMT, in minutes.
*/
private void init(Date date, int nanoseconds, int timeZone,
int defaultedTimeZone) {
// Shouldn't happen, but just in case...
if (earlyException != null)
throw earlyException;
// Make a new Date object
this.value = (Date) date.clone();
// Combine the nanoseconds so they are between 0 and 999,999,999
this.nanoseconds = combineNanos(this.value, nanoseconds);
this.timeZone = timeZone;
this.defaultedTimeZone = defaultedTimeZone;
}
/**
* Returns a new <code>DateTimeAttribute</code> that represents
* the xs:dateTime at a particular DOM node.
*
* @param root the <code>Node</code> that contains the desired value
* @return a new <code>DateTimeAttribute</code> representing the
* appropriate value
* @throws ParsingException if any problems occurred while parsing
*/
public static DateTimeAttribute getInstance(Node root)
throws ParsingException, NumberFormatException, ParseException
{
return getInstance(root.getFirstChild().getNodeValue());
}
/**
* Returns a new <code>DateTimeAttribute</code> that represents
* the xs:dateTime value indicated by the string provided.
*
* @param value a string representing the desired value
* @return a new <code>DateTimeAttribute</code> representing the
* desired value
* @throws ParsingException if the text is formatted incorrectly
* @throws NumberFormatException if the nanosecond format is incorrect
* @throws ParseException
*/
public static DateTimeAttribute getInstance(String value)
throws ParsingException, NumberFormatException, ParseException
{
Date dateValue = null;
int nanoseconds = 0;
int timeZone;
int defaultedTimeZone;
initParsers();
// If string ends with Z, it's in GMT. Chop off the Z and
// add +00:00 to make the time zone explicit.
if (value.endsWith("Z"))
value = value.substring(0, value.length()-1) + "+00:00";
// Figure out if the string has a time zone.
// If string ends with +XX:XX or -XX:XX, it must have
// a time zone or be invalid.
int len = value.length(); // This variable is often not up-to-date
boolean hasTimeZone = ((value.charAt(len-3) == ':') &&
((value.charAt(len-6) == '-') ||
(value.charAt(len-6) == '+')));
// If string contains a period, it must have fractional
// seconds (or be invalid). Strip them out and put the
// value in nanoseconds.
int dotIndex = value.indexOf('.');
if (dotIndex != -1) {
// Decide where fractional seconds end.
int secondsEnd = value.length();
if (hasTimeZone)
secondsEnd -= 6;
// Copy the fractional seconds out of the string.
String nanoString = value.substring(dotIndex+1, secondsEnd);
// Check that all those characters are ASCII digits.
for (int i = nanoString.length()-1; i >= 0; i--) {
char c = nanoString.charAt(i);
if ((c < '0') || (c > '9'))
throw new ParsingException("non-ascii digit found");
}
// If there are less than 9 digits in the fractional seconds,
// pad with zeros on the right so it's nanoseconds.
while (nanoString.length() < 9)
nanoString += "0";
// If there are more than 9 digits in the fractional seconds,
// drop the least significant digits.
if (nanoString.length() > 9) {
nanoString = nanoString.substring(0, 9);
}
// Parse the fractional seconds.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -