All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.xmlbeans.XmlCalendar Maven / Gradle / Ivy

There is a newer version: 5.2.0_1
Show newest version
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package org.apache.xmlbeans;

import org.apache.xmlbeans.impl.util.SuppressForbidden;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * An XML Schema compatible subclass of {@link java.util.GregorianCalendar GregorianCalendar}.
 * XmlCalendar modifies several key details in the behavior of
 * GregorianCalendar to make it more useful when dealing with XML dates.
 * 

* It is easy to convert between XmlCalendar and {@link GDate}, or to * parse or emit an XmlCalendar using a standard XML Schema * lexical representation. *

    *
  1. * To match XML Schema dates, this XmlCalendar is a fully proleptic * Gregorian calendar by default, which means that Gregorian calendar * rules are applied backwards in time as if they had always been in * effect, actual historical circumstances concerning the observance * of the 1582 decree of Pope Gregory XIII notwithstanding. *
  2. *
  3. * In order to better support partially-specified dates for XML Schema, * this implementation provides a stable get(field) method * that does not modify the instance if you are acessing a field right * after it was explicitly set: a set followed by a get will always * return the same thing and will not fill in any other fields. However, * if you get a field that was not explicitly set, then all the fields * are still automatically filled and normalized for you, just like a * regular GregorianCalendar. If you wish to force the completion and * defaulting of all the fields (without hunting to get one that happens * to be unset), you can always do so by calling getTime(). *
  4. *
  5. * When a year is unspecified and needs to be filled in automatically * (for example when using a .get or .getTime method as discussed above), * the year is defaulted to year 0 (also known as 1 BC). This is different * from {@link GregorianCalendar}, which chooses 1970. The reason 0 is preferable * is that it is a leap year and so it permits the date --2-29 to be specified * stably. A different default year can be chosen via the static method * {@link #setDefaultYear(int) XmlCalendar.setDefaultYear()}, or by setting the * system property "user.defaultyear". If you do change this value, you should * pick another leap year such as 2000 and avoid non-leap years such as 1900. *
  6. *
  7. * When constructing an XmlCalendar from an XML Schema * formatted date or time string or GDate object, the timezone * for the calendar is taken from the string if it is present, or * taken to be {@link java.util.TimeZone#getDefault() TimeZone.getDefault()} if not. *

    * For example, the XML timezone "Z" is translated to "GMT"; * the XML timezone "+05:00" is translated to "GMT+05:00". *

    *
  8. *
  9. * Finally, this implementation provides a String constructor and a * toString() method that comply with the XML Schema conventions * for formatting a date. If only a subset of fields have been * explicitly set, toString() produces a string with the proper subset * of information. *
  10. *
*/ public class XmlCalendar extends GregorianCalendar { private static int defaultYear = Integer.MIN_VALUE; private static final int DEFAULT_DEFAULT_YEAR = 0; private static final Date _beginningOfTime = new Date(Long.MIN_VALUE); /** * Constructs an XmlCalendar for a standard XML * schema formatted date string. * * The parser accepts any of the following formats: * * YYYY-MM-DDThh:mm:ss - dateTime * YYYY-MM-DD - date * hh:mm:ss - time * YYYY - gYear * --MM - gMonth * ---DD - gDay * * The parser actually accepts all 16 combinations of subsets of * fields (Y, M, D, T) using the same scheme, even for combinations * that are not defined as types in the schema spec, such as * year, day, and time: * * YYYY--DDThh:mm:ss - [everything but month specified] * * In the string, each field must be padded to its full width, for * example, January must be --01, not just --1. * * In particular, a year must be padded to at least four digits, so * "98" is not a valid year, although "1998" and "0098" are both valid * years, unambiguously 19 centuries separated from each other. A year * may also be preceded by a minus symbol: -0001 is 1 BC and -0002 is * 2 BC. * * Finally a timezone is always allowed (yet optional) at the end. * Timezones must be either "Z" (UTC, which we translate to GMT), * or simple offsets from UTC in the range "-14:00" to "+14:00", * for example: "14:30:00-05:00" specifies 2:30 PM in the * afternoon at UTC-05:00, which is the same as EST. * * If a timezone is not specified, the default TimeZone is used. */ public XmlCalendar(String xmlSchemaDateString) { this(new GDate(xmlSchemaDateString)); // use GDate to parse } /** * Constructs an XmlCalendar from a GDate. * * If the instance is not completed, you can round-trip to an * equivalent GDate by writing "new GDate(new XmlCalendar(gdate))". * However, if you access any of the unset fields of the calendar, all * the fields will be automatically filled in, so partial dates * without timezones or other fields will not round-trip after access. */ public XmlCalendar(GDateSpecification date) { this(GDate.timeZoneForGDate(date), date); } @SuppressForbidden("Locale is not known and we don't have a general class to set the default locale") private XmlCalendar(TimeZone tz, GDateSpecification date) { super(tz); setGregorianChange(_beginningOfTime); // proleptic clear(); if (date.hasYear()) { int y = date.getYear(); // is never 0 if (y > 0) { set(Calendar.ERA, GregorianCalendar.AD); } else // y < 0 { set(Calendar.ERA, GregorianCalendar.BC); //y = 1 - y; y = -y; // no need to add 1 } set(Calendar.YEAR, y); } if (date.hasMonth()) set(Calendar.MONTH, date.getMonth() - 1); // note!! if (date.hasDay()) set(Calendar.DAY_OF_MONTH, date.getDay()); if (date.hasTime()) { set(Calendar.HOUR_OF_DAY, date.getHour()); set(Calendar.MINUTE, date.getMinute()); set(Calendar.SECOND, date.getSecond()); if (date.getFraction().scale() > 0) set(Calendar.MILLISECOND, date.getMillisecond()); } if (date.hasTimeZone()) { set(Calendar.ZONE_OFFSET, date.getTimeZoneSign() * 1000 * 60 * (date.getTimeZoneHour() * 60 + date.getTimeZoneMinute())); set(Calendar.DST_OFFSET, 0); // note!! if we don't do this, then GregorianCalendar will pick up DST from the time zone } } /** * Constructs an XmlCalendar from a Date. * * The default TimeZone is used for computing the various fields. */ public XmlCalendar(Date date) { this(TimeZone.getDefault(), new GDate(date)); complete(); } /** * Constructs an XmlCalendar with the specified year, month, day, * hours, minutes, seconds, and optional fractional seconds, in * the default timezone. */ public XmlCalendar( int year, int month, int day, int hour, int minute, int second, BigDecimal fraction) { this(TimeZone.getDefault(), new GDate(year, month, day, hour, minute, second, fraction)); } /** * Constructs an XmlCalendar with the specified year, month, day, * hours, minutes, seconds, and optional fractional seconds, in * the specified timezone. */ public XmlCalendar( int year, int month, int day, int hour, int minute, int second, BigDecimal fraction, int tzSign, int tzHour, int tzMinute) { this(new GDate(year, month, day, hour, minute, second, fraction, tzSign, tzHour, tzMinute)); } /** * Gets the value for a given time field. * * Unlike the GregorianCalendar implementation, the get() does not * force a complete of all fields. If you wish to force a completion * of all the fields, call getTime() first. */ public int get(int field) { if (!isSet(field) || isTimeSet) return super.get(field); // forces a complete else return internalGet(field); // does not force a complete. } /** * Constructs an empty instance with no fields set. */ @SuppressForbidden("Locale is not known and we don't have a general class to set the default locale") public XmlCalendar() { setGregorianChange(_beginningOfTime); // proleptic clear(); } /** * Returns the default year that is used when no year is specified. */ public static int getDefaultYear() { if (defaultYear == Integer.MIN_VALUE) { try { String yearstring = SystemProperties.getProperty("user.defaultyear"); if (yearstring != null) defaultYear = Integer.parseInt(yearstring); else defaultYear = DEFAULT_DEFAULT_YEAR; } catch (Throwable t) { defaultYear = DEFAULT_DEFAULT_YEAR; } } return defaultYear; } /** * Sets the default year to be used when no year is specified. */ public static void setDefaultYear(int year) { defaultYear = year; } /** * Overrides GregorianCalendar.computeTime to apply a different * default year. (It must be a leap year.) */ protected void computeTime() { boolean unsetYear = !isSet(YEAR); if (unsetYear) set(YEAR, getDefaultYear()); try { super.computeTime(); } finally { if (unsetYear) clear(YEAR); } } /** * Prints the XmlCalendar using a standard XML Schema * format, as described in XmlCalendar(String s). */ public String toString() { return (new GDate(this)).toString(); // use GDate to print } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy