0001: /*
0002: * Copyright 2001-2006 Stephen Colebourne
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.joda.time.format;
0017:
0018: import java.util.Collection;
0019:
0020: import org.joda.time.DateTimeFieldType;
0021: import org.joda.time.DateTimeZone;
0022:
0023: /**
0024: * Factory that creates instances of DateTimeFormatter for the ISO8601 standard.
0025: * <p>
0026: * Datetime formatting is performed by the {@link DateTimeFormatter} class.
0027: * Three classes provide factory methods to create formatters, and this is one.
0028: * The others are {@link DateTimeFormat} and {@link DateTimeFormatterBuilder}.
0029: * <p>
0030: * ISO8601 is the international standard for data interchange. It defines a
0031: * framework, rather than an absolute standard. As a result this provider has a
0032: * number of methods that represent common uses of the framework. The most common
0033: * formats are {@link #date() date}, {@link #time() time}, and {@link #dateTime() dateTime}.
0034: * <p>
0035: * For example, to format a date time in ISO format:
0036: * <pre>
0037: * DateTime dt = new DateTime();
0038: * DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
0039: * String str = fmt.print(dt);
0040: * </pre>
0041: * <p>
0042: * It is important to understand that these formatters are not linked to
0043: * the <code>ISOChronology</code>. These formatters may be used with any
0044: * chronology, however there may be certain side effects with more unusual
0045: * chronologies. For example, the ISO formatters rely on dayOfWeek being
0046: * single digit, dayOfMonth being two digit and dayOfYear being three digit.
0047: * A chronology with a ten day week would thus cause issues. However, in
0048: * general, it is safe to use these formatters with other chronologies.
0049: * <p>
0050: * ISODateTimeFormat is thread-safe and immutable, and the formatters it
0051: * returns are as well.
0052: *
0053: * @author Brian S O'Neill
0054: * @since 1.0
0055: * @see DateTimeFormat
0056: * @see DateTimeFormatterBuilder
0057: */
0058: public class ISODateTimeFormat {
0059:
0060: //-----------------------------------------------------------------------
0061: private static DateTimeFormatter ye, // year element (yyyy)
0062: mye, // monthOfYear element (-MM)
0063: dme, // dayOfMonth element (-dd)
0064: we, // weekyear element (xxxx)
0065: wwe, // weekOfWeekyear element (-ww)
0066: dwe, // dayOfWeek element (-ee)
0067: dye, // dayOfYear element (-DDD)
0068: hde, // hourOfDay element (HH)
0069: mhe, // minuteOfHour element (:mm)
0070: sme, // secondOfMinute element (:ss)
0071: lse, // millisOfSecond element (.SSS)
0072: fse, // fractionOfSecond element (.SSSSSSSSS)
0073: ze, // zone offset element
0074: lte, // literal 'T' element
0075:
0076: //y, // year (same as year element)
0077: ym, // year month
0078: ymd, // year month day
0079:
0080: //w, // weekyear (same as weekyear element)
0081: ww, // weekyear week
0082: wwd, // weekyear week day
0083:
0084: //h, // hour (same as hour element)
0085: hm, // hour minute
0086: hms, // hour minute second
0087: hmsl, // hour minute second millis
0088: hmsf, // hour minute second fraction
0089:
0090: dh, // date hour
0091: dhm, // date hour minute
0092: dhms, // date hour minute second
0093: dhmsl, // date hour minute second millis
0094: dhmsf, // date hour minute second fraction
0095:
0096: //d, // date (same as ymd)
0097: t, // time
0098: tx, // time no millis
0099: tt, // Ttime
0100: ttx, // Ttime no millis
0101: dt, // date time
0102: dtx, // date time no millis
0103:
0104: //wd, // week date (same as wwd)
0105: wdt, // week date time
0106: wdtx, // week date time no millis
0107:
0108: od, // ordinal date (same as yd)
0109: odt, // ordinal date time
0110: odtx, // ordinal date time no millis
0111:
0112: bd, // basic date
0113: bt, // basic time
0114: btx, // basic time no millis
0115: btt, // basic Ttime
0116: bttx, // basic Ttime no millis
0117: bdt, // basic date time
0118: bdtx, // basic date time no millis
0119:
0120: bod, // basic ordinal date
0121: bodt, // basic ordinal date time
0122: bodtx, // basic ordinal date time no millis
0123:
0124: bwd, // basic week date
0125: bwdt, // basic week date time
0126: bwdtx, // basic week date time no millis
0127:
0128: dpe, // date parser element
0129: tpe, // time parser element
0130: dp, // date parser
0131: ldp, // local date parser
0132: tp, // time parser
0133: ltp, // local time parser
0134: dtp, // date time parser
0135: dotp, // date optional time parser
0136: ldotp; // local date optional time parser
0137:
0138: /**
0139: * Constructor.
0140: *
0141: * @since 1.1 (previously private)
0142: */
0143: protected ISODateTimeFormat() {
0144: super ();
0145: }
0146:
0147: //-----------------------------------------------------------------------
0148: /**
0149: * Returns a formatter that outputs only those fields specified.
0150: * <p>
0151: * This method examines the fields provided and returns an ISO-style
0152: * formatter that best fits. This can be useful for outputting
0153: * less-common ISO styles, such as YearMonth (YYYY-MM) or MonthDay (--MM-DD).
0154: * <p>
0155: * The list provided may have overlapping fields, such as dayOfWeek and
0156: * dayOfMonth. In this case, the style is chosen based on the following
0157: * list, thus in the example, the calendar style is chosen as dayOfMonth
0158: * is higher in priority than dayOfWeek:
0159: * <ul>
0160: * <li>monthOfYear - calendar date style
0161: * <li>dayOfYear - ordinal date style
0162: * <li>weekOfWeekYear - week date style
0163: * <li>dayOfMonth - calendar date style
0164: * <li>dayOfWeek - week date style
0165: * <li>year
0166: * <li>weekyear
0167: * </ul>
0168: * The supported formats are:
0169: * <pre>
0170: * Extended Basic Fields
0171: * 2005-03-25 20050325 year/monthOfYear/dayOfMonth
0172: * 2005-03 2005-03 year/monthOfYear
0173: * 2005--25 2005--25 year/dayOfMonth *
0174: * 2005 2005 year
0175: * --03-25 --0325 monthOfYear/dayOfMonth
0176: * --03 --03 monthOfYear
0177: * ---03 ---03 dayOfMonth
0178: * 2005-084 2005084 year/dayOfYear
0179: * -084 -084 dayOfYear
0180: * 2005-W12-5 2005W125 weekyear/weekOfWeekyear/dayOfWeek
0181: * 2005-W-5 2005W-5 weekyear/dayOfWeek *
0182: * 2005-W12 2005W12 weekyear/weekOfWeekyear
0183: * -W12-5 -W125 weekOfWeekyear/dayOfWeek
0184: * -W12 -W12 weekOfWeekyear
0185: * -W-5 -W-5 dayOfWeek
0186: * 10:20:30.040 102030.040 hour/minute/second/milli
0187: * 10:20:30 102030 hour/minute/second
0188: * 10:20 1020 hour/minute
0189: * 10 10 hour
0190: * -20:30.040 -2030.040 minute/second/milli
0191: * -20:30 -2030 minute/second
0192: * -20 -20 minute
0193: * --30.040 --30.040 second/milli
0194: * --30 --30 second
0195: * ---.040 ---.040 milli *
0196: * 10-30.040 10-30.040 hour/second/milli *
0197: * 10:20-.040 1020-.040 hour/minute/milli *
0198: * 10-30 10-30 hour/second *
0199: * 10--.040 10--.040 hour/milli *
0200: * -20-.040 -20-.040 minute/milli *
0201: * plus datetime formats like {date}T{time}
0202: * </pre>
0203: * * indiates that this is not an official ISO format and can be excluded
0204: * by passing in <code>strictISO</code> as <code>true</code>.
0205: *
0206: * @param fields the fields to get a formatter for, not null,
0207: * updated by the method call, which removes those fields built in the formatter
0208: * @param extended true to use the extended format (with separators)
0209: * @param strictISO true to stick exactly to ISO8601, false to include additional formats
0210: * @return a suitable formatter
0211: * @throws IllegalArgumentException if there is no format for the fields
0212: * @since 1.1
0213: */
0214: public static DateTimeFormatter forFields(Collection fields,
0215: boolean extended, boolean strictISO) {
0216:
0217: if (fields == null || fields.size() == 0) {
0218: throw new IllegalArgumentException(
0219: "The fields must not be null or empty");
0220: }
0221: int inputSize = fields.size();
0222: boolean reducedPrec = false;
0223: DateTimeFormatterBuilder bld = new DateTimeFormatterBuilder();
0224: // date
0225: if (fields.contains(DateTimeFieldType.monthOfYear())) {
0226: reducedPrec = dateByMonth(bld, fields, extended, strictISO);
0227: } else if (fields.contains(DateTimeFieldType.dayOfYear())) {
0228: reducedPrec = dateByOrdinal(bld, fields, extended,
0229: strictISO);
0230: } else if (fields.contains(DateTimeFieldType.weekOfWeekyear())) {
0231: reducedPrec = dateByWeek(bld, fields, extended, strictISO);
0232: } else if (fields.contains(DateTimeFieldType.dayOfMonth())) {
0233: reducedPrec = dateByMonth(bld, fields, extended, strictISO);
0234: } else if (fields.contains(DateTimeFieldType.dayOfWeek())) {
0235: reducedPrec = dateByWeek(bld, fields, extended, strictISO);
0236: } else if (fields.remove(DateTimeFieldType.year())) {
0237: bld.append(yearElement());
0238: reducedPrec = true;
0239: } else if (fields.remove(DateTimeFieldType.weekyear())) {
0240: bld.append(weekyearElement());
0241: reducedPrec = true;
0242: }
0243: boolean datePresent = (fields.size() < inputSize);
0244:
0245: // time
0246: time(bld, fields, extended, strictISO, reducedPrec, datePresent);
0247:
0248: // result
0249: if (bld.canBuildFormatter() == false) {
0250: throw new IllegalArgumentException(
0251: "No valid format for fields: " + fields);
0252: }
0253: return bld.toFormatter();
0254: }
0255:
0256: //-----------------------------------------------------------------------
0257: /**
0258: * Creates a date using the calendar date format.
0259: * Specification reference: 5.2.1.
0260: *
0261: * @param bld the builder
0262: * @param fields the fields
0263: * @param extended true to use extended format
0264: * @param strictISO true to only allow ISO formats
0265: * @return true if reduced precision
0266: * @since 1.1
0267: */
0268: private static boolean dateByMonth(DateTimeFormatterBuilder bld,
0269: Collection fields, boolean extended, boolean strictISO) {
0270:
0271: boolean reducedPrec = false;
0272: if (fields.remove(DateTimeFieldType.year())) {
0273: bld.append(yearElement());
0274: if (fields.remove(DateTimeFieldType.monthOfYear())) {
0275: if (fields.remove(DateTimeFieldType.dayOfMonth())) {
0276: // YYYY-MM-DD/YYYYMMDD
0277: appendSeparator(bld, extended);
0278: bld.appendMonthOfYear(2);
0279: appendSeparator(bld, extended);
0280: bld.appendDayOfMonth(2);
0281: } else {
0282: // YYYY-MM/YYYY-MM
0283: bld.appendLiteral('-');
0284: bld.appendMonthOfYear(2);
0285: reducedPrec = true;
0286: }
0287: } else {
0288: if (fields.remove(DateTimeFieldType.dayOfMonth())) {
0289: // YYYY--DD/YYYY--DD (non-iso)
0290: checkNotStrictISO(fields, strictISO);
0291: bld.appendLiteral('-');
0292: bld.appendLiteral('-');
0293: bld.appendDayOfMonth(2);
0294: } else {
0295: // YYYY/YYYY
0296: reducedPrec = true;
0297: }
0298: }
0299:
0300: } else if (fields.remove(DateTimeFieldType.monthOfYear())) {
0301: bld.appendLiteral('-');
0302: bld.appendLiteral('-');
0303: bld.appendMonthOfYear(2);
0304: if (fields.remove(DateTimeFieldType.dayOfMonth())) {
0305: // --MM-DD/--MMDD
0306: appendSeparator(bld, extended);
0307: bld.appendDayOfMonth(2);
0308: } else {
0309: // --MM/--MM
0310: reducedPrec = true;
0311: }
0312: } else if (fields.remove(DateTimeFieldType.dayOfMonth())) {
0313: // ---DD/---DD
0314: bld.appendLiteral('-');
0315: bld.appendLiteral('-');
0316: bld.appendLiteral('-');
0317: bld.appendDayOfMonth(2);
0318: }
0319: return reducedPrec;
0320: }
0321:
0322: //-----------------------------------------------------------------------
0323: /**
0324: * Creates a date using the ordinal date format.
0325: * Specification reference: 5.2.2.
0326: *
0327: * @param bld the builder
0328: * @param fields the fields
0329: * @param extended true to use extended format
0330: * @param strictISO true to only allow ISO formats
0331: * @since 1.1
0332: */
0333: private static boolean dateByOrdinal(DateTimeFormatterBuilder bld,
0334: Collection fields, boolean extended, boolean strictISO) {
0335:
0336: boolean reducedPrec = false;
0337: if (fields.remove(DateTimeFieldType.year())) {
0338: bld.append(yearElement());
0339: if (fields.remove(DateTimeFieldType.dayOfYear())) {
0340: // YYYY-DDD/YYYYDDD
0341: appendSeparator(bld, extended);
0342: bld.appendDayOfYear(3);
0343: } else {
0344: // YYYY/YYYY
0345: reducedPrec = true;
0346: }
0347:
0348: } else if (fields.remove(DateTimeFieldType.dayOfYear())) {
0349: // -DDD/-DDD
0350: bld.appendLiteral('-');
0351: bld.appendDayOfYear(3);
0352: }
0353: return reducedPrec;
0354: }
0355:
0356: //-----------------------------------------------------------------------
0357: /**
0358: * Creates a date using the calendar date format.
0359: * Specification reference: 5.2.3.
0360: *
0361: * @param bld the builder
0362: * @param fields the fields
0363: * @param extended true to use extended format
0364: * @param strictISO true to only allow ISO formats
0365: * @since 1.1
0366: */
0367: private static boolean dateByWeek(DateTimeFormatterBuilder bld,
0368: Collection fields, boolean extended, boolean strictISO) {
0369:
0370: boolean reducedPrec = false;
0371: if (fields.remove(DateTimeFieldType.weekyear())) {
0372: bld.append(weekyearElement());
0373: if (fields.remove(DateTimeFieldType.weekOfWeekyear())) {
0374: appendSeparator(bld, extended);
0375: bld.appendLiteral('W');
0376: bld.appendWeekOfWeekyear(2);
0377: if (fields.remove(DateTimeFieldType.dayOfWeek())) {
0378: // YYYY-WWW-D/YYYYWWWD
0379: appendSeparator(bld, extended);
0380: bld.appendDayOfWeek(1);
0381: } else {
0382: // YYYY-WWW/YYYY-WWW
0383: reducedPrec = true;
0384: }
0385: } else {
0386: if (fields.remove(DateTimeFieldType.dayOfWeek())) {
0387: // YYYY-W-D/YYYYW-D (non-iso)
0388: checkNotStrictISO(fields, strictISO);
0389: appendSeparator(bld, extended);
0390: bld.appendLiteral('W');
0391: bld.appendLiteral('-');
0392: bld.appendDayOfWeek(1);
0393: } else {
0394: // YYYY/YYYY
0395: reducedPrec = true;
0396: }
0397: }
0398:
0399: } else if (fields.remove(DateTimeFieldType.weekOfWeekyear())) {
0400: bld.appendLiteral('-');
0401: bld.appendLiteral('W');
0402: bld.appendWeekOfWeekyear(2);
0403: if (fields.remove(DateTimeFieldType.dayOfWeek())) {
0404: // -WWW-D/-WWWD
0405: appendSeparator(bld, extended);
0406: bld.appendDayOfWeek(1);
0407: } else {
0408: // -WWW/-WWW
0409: reducedPrec = true;
0410: }
0411: } else if (fields.remove(DateTimeFieldType.dayOfWeek())) {
0412: // -W-D/-W-D
0413: bld.appendLiteral('-');
0414: bld.appendLiteral('W');
0415: bld.appendLiteral('-');
0416: bld.appendDayOfWeek(1);
0417: }
0418: return reducedPrec;
0419: }
0420:
0421: //-----------------------------------------------------------------------
0422: /**
0423: * Adds the time fields to the builder.
0424: * Specification reference: 5.3.1.
0425: *
0426: * @param bld the builder
0427: * @param fields the fields
0428: * @param extended whether to use the extended format
0429: * @param strictISO whether to be strict
0430: * @param reducedPrec whether the date was reduced precision
0431: * @param datePresent whether there was a date
0432: * @since 1.1
0433: */
0434: private static void time(DateTimeFormatterBuilder bld,
0435: Collection fields, boolean extended, boolean strictISO,
0436: boolean reducedPrec, boolean datePresent) {
0437:
0438: boolean hour = fields.remove(DateTimeFieldType.hourOfDay());
0439: boolean minute = fields
0440: .remove(DateTimeFieldType.minuteOfHour());
0441: boolean second = fields.remove(DateTimeFieldType
0442: .secondOfMinute());
0443: boolean milli = fields.remove(DateTimeFieldType
0444: .millisOfSecond());
0445: if (!hour && !minute && !second && !milli) {
0446: return;
0447: }
0448: if (hour || minute || second || milli) {
0449: if (strictISO && reducedPrec) {
0450: throw new IllegalArgumentException(
0451: "No valid ISO8601 format for fields because Date was reduced precision: "
0452: + fields);
0453: }
0454: if (datePresent) {
0455: bld.appendLiteral('T');
0456: }
0457: }
0458: if (hour && minute && second || (hour && !second && !milli)) {
0459: // OK - HMSm/HMS/HM/H - valid in combination with date
0460: } else {
0461: if (strictISO && datePresent) {
0462: throw new IllegalArgumentException(
0463: "No valid ISO8601 format for fields because Time was truncated: "
0464: + fields);
0465: }
0466: if (!hour
0467: && (minute && second || (minute && !milli) || second)) {
0468: // OK - MSm/MS/M/Sm/S - valid ISO formats
0469: } else {
0470: if (strictISO) {
0471: throw new IllegalArgumentException(
0472: "No valid ISO8601 format for fields: "
0473: + fields);
0474: }
0475: }
0476: }
0477: if (hour) {
0478: bld.appendHourOfDay(2);
0479: } else if (minute || second || milli) {
0480: bld.appendLiteral('-');
0481: }
0482: if (extended && hour && minute) {
0483: bld.appendLiteral(':');
0484: }
0485: if (minute) {
0486: bld.appendMinuteOfHour(2);
0487: } else if (second || milli) {
0488: bld.appendLiteral('-');
0489: }
0490: if (extended && minute && second) {
0491: bld.appendLiteral(':');
0492: }
0493: if (second) {
0494: bld.appendSecondOfMinute(2);
0495: } else if (milli) {
0496: bld.appendLiteral('-');
0497: }
0498: if (milli) {
0499: bld.appendLiteral('.');
0500: bld.appendMillisOfSecond(3);
0501: }
0502: }
0503:
0504: //-----------------------------------------------------------------------
0505: /**
0506: * Checks that the iso only flag is not set, throwing an exception if it is.
0507: *
0508: * @param fields the fields
0509: * @param strictISO true if only ISO formats allowed
0510: * @since 1.1
0511: */
0512: private static void checkNotStrictISO(Collection fields,
0513: boolean strictISO) {
0514: if (strictISO) {
0515: throw new IllegalArgumentException(
0516: "No valid ISO8601 format for fields: " + fields);
0517: }
0518: }
0519:
0520: /**
0521: * Appends the separator if necessary.
0522: *
0523: * @param bld the builder
0524: * @param extended whether to append the separator
0525: * @param sep the separator
0526: * @since 1.1
0527: */
0528: private static void appendSeparator(DateTimeFormatterBuilder bld,
0529: boolean extended) {
0530: if (extended) {
0531: bld.appendLiteral('-');
0532: }
0533: }
0534:
0535: //-----------------------------------------------------------------------
0536: /**
0537: * Returns a generic ISO date parser for parsing dates with a possible zone.
0538: * It accepts formats described by the following syntax:
0539: * <pre>
0540: * date = date-element ['T' offset]
0541: * date-element = std-date-element | ord-date-element | week-date-element
0542: * std-date-element = yyyy ['-' MM ['-' dd]]
0543: * ord-date-element = yyyy ['-' DDD]
0544: * week-date-element = xxxx '-W' ww ['-' e]
0545: * offset = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
0546: * </pre>
0547: */
0548: public static DateTimeFormatter dateParser() {
0549: if (dp == null) {
0550: DateTimeParser tOffset = new DateTimeFormatterBuilder()
0551: .appendLiteral('T').append(offsetElement())
0552: .toParser();
0553: dp = new DateTimeFormatterBuilder().append(
0554: dateElementParser()).appendOptional(tOffset)
0555: .toFormatter();
0556: }
0557: return dp;
0558: }
0559:
0560: /**
0561: * Returns a generic ISO date parser for parsing local dates.
0562: * This parser is initialised with the local (UTC) time zone.
0563: * <p>
0564: * It accepts formats described by the following syntax:
0565: * <pre>
0566: * date-element = std-date-element | ord-date-element | week-date-element
0567: * std-date-element = yyyy ['-' MM ['-' dd]]
0568: * ord-date-element = yyyy ['-' DDD]
0569: * week-date-element = xxxx '-W' ww ['-' e]
0570: * </pre>
0571: * @since 1.3
0572: */
0573: public static DateTimeFormatter localDateParser() {
0574: if (ldp == null) {
0575: ldp = dateElementParser().withZone(DateTimeZone.UTC);
0576: }
0577: return ldp;
0578: }
0579:
0580: /**
0581: * Returns a generic ISO date parser for parsing dates.
0582: * It accepts formats described by the following syntax:
0583: * <pre>
0584: * date-element = std-date-element | ord-date-element | week-date-element
0585: * std-date-element = yyyy ['-' MM ['-' dd]]
0586: * ord-date-element = yyyy ['-' DDD]
0587: * week-date-element = xxxx '-W' ww ['-' e]
0588: * </pre>
0589: */
0590: public static DateTimeFormatter dateElementParser() {
0591: if (dpe == null) {
0592: dpe = new DateTimeFormatterBuilder()
0593: .append(
0594: null,
0595: new DateTimeParser[] {
0596: new DateTimeFormatterBuilder()
0597: .append(yearElement())
0598: .appendOptional(
0599: new DateTimeFormatterBuilder()
0600: .append(
0601: monthElement())
0602: .appendOptional(
0603: dayOfMonthElement()
0604: .getParser())
0605: .toParser())
0606: .toParser(),
0607: new DateTimeFormatterBuilder()
0608: .append(weekyearElement())
0609: .append(weekElement())
0610: .appendOptional(
0611: dayOfWeekElement()
0612: .getParser())
0613: .toParser(),
0614: new DateTimeFormatterBuilder()
0615: .append(yearElement())
0616: .append(dayOfYearElement())
0617: .toParser() })
0618: .toFormatter();
0619: }
0620: return dpe;
0621: }
0622:
0623: /**
0624: * Returns a generic ISO time parser for parsing times with a possible zone.
0625: * It accepts formats described by the following syntax:
0626: * <pre>
0627: * time = ['T'] time-element [offset]
0628: * time-element = HH [minute-element] | [fraction]
0629: * minute-element = ':' mm [second-element] | [fraction]
0630: * second-element = ':' ss [fraction]
0631: * fraction = ('.' | ',') digit+
0632: * offset = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
0633: * </pre>
0634: */
0635: public static DateTimeFormatter timeParser() {
0636: if (tp == null) {
0637: tp = new DateTimeFormatterBuilder().appendOptional(
0638: literalTElement().getParser()).append(
0639: timeElementParser()).appendOptional(
0640: offsetElement().getParser()).toFormatter();
0641: }
0642: return tp;
0643: }
0644:
0645: /**
0646: * Returns a generic ISO time parser for parsing local times.
0647: * This parser is initialised with the local (UTC) time zone.
0648: * <p>
0649: * It accepts formats described by the following syntax:
0650: * <pre>
0651: * time = ['T'] time-element
0652: * time-element = HH [minute-element] | [fraction]
0653: * minute-element = ':' mm [second-element] | [fraction]
0654: * second-element = ':' ss [fraction]
0655: * fraction = ('.' | ',') digit+
0656: * </pre>
0657: * @since 1.3
0658: */
0659: public static DateTimeFormatter localTimeParser() {
0660: if (ltp == null) {
0661: ltp = new DateTimeFormatterBuilder().appendOptional(
0662: literalTElement().getParser()).append(
0663: timeElementParser()).toFormatter().withZone(
0664: DateTimeZone.UTC);
0665: }
0666: return ltp;
0667: }
0668:
0669: /**
0670: * Returns a generic ISO time parser. It accepts formats described by
0671: * the following syntax:
0672: * <pre>
0673: * time-element = HH [minute-element] | [fraction]
0674: * minute-element = ':' mm [second-element] | [fraction]
0675: * second-element = ':' ss [fraction]
0676: * fraction = ('.' | ',') digit+
0677: * </pre>
0678: */
0679: public static DateTimeFormatter timeElementParser() {
0680: if (tpe == null) {
0681: // Decimal point can be either '.' or ','
0682: DateTimeParser decimalPoint = new DateTimeFormatterBuilder()
0683: .append(
0684: null,
0685: new DateTimeParser[] {
0686: new DateTimeFormatterBuilder()
0687: .appendLiteral('.')
0688: .toParser(),
0689: new DateTimeFormatterBuilder()
0690: .appendLiteral(',')
0691: .toParser() }).toParser();
0692:
0693: tpe = new DateTimeFormatterBuilder()
0694: // time-element
0695: .append(hourElement())
0696: .append(
0697: null,
0698: new DateTimeParser[] {
0699: new DateTimeFormatterBuilder()
0700: // minute-element
0701: .append(minuteElement())
0702: .append(
0703: null,
0704: new DateTimeParser[] {
0705: new DateTimeFormatterBuilder()
0706: // second-element
0707: .append(
0708: secondElement())
0709: // second fraction
0710: .appendOptional(
0711: new DateTimeFormatterBuilder()
0712: .append(
0713: decimalPoint)
0714: .appendFractionOfSecond(
0715: 1,
0716: 9)
0717: .toParser())
0718: .toParser(),
0719: // minute fraction
0720: new DateTimeFormatterBuilder()
0721: .append(
0722: decimalPoint)
0723: .appendFractionOfMinute(
0724: 1,
0725: 9)
0726: .toParser(),
0727: null })
0728: .toParser(),
0729: // hour fraction
0730: new DateTimeFormatterBuilder()
0731: .append(decimalPoint)
0732: .appendFractionOfHour(1, 9)
0733: .toParser(), null })
0734: .toFormatter();
0735: }
0736: return tpe;
0737: }
0738:
0739: /**
0740: * Returns a generic ISO datetime parser which parses either a date or
0741: * a time or both. It accepts formats described by the following syntax:
0742: * <pre>
0743: * datetime = time | date-opt-time
0744: * time = 'T' time-element [offset]
0745: * date-opt-time = date-element ['T' [time-element] [offset]]
0746: * date-element = std-date-element | ord-date-element | week-date-element
0747: * std-date-element = yyyy ['-' MM ['-' dd]]
0748: * ord-date-element = yyyy ['-' DDD]
0749: * week-date-element = xxxx '-W' ww ['-' e]
0750: * time-element = HH [minute-element] | [fraction]
0751: * minute-element = ':' mm [second-element] | [fraction]
0752: * second-element = ':' ss [fraction]
0753: * fraction = ('.' | ',') digit+
0754: * offset = 'Z' | (('+' | '-') HH [':' mm [':' ss [('.' | ',') SSS]]])
0755: * </pre>
0756: */
0757: public static DateTimeFormatter dateTimeParser() {
0758: if (dtp == null) {
0759: // This is different from the general time parser in that the 'T'
0760: // is required.
0761: DateTimeParser time = new DateTimeFormatterBuilder()
0762: .appendLiteral('T').append(timeElementParser())
0763: .appendOptional(offsetElement().getParser())
0764: .toParser();
0765: dtp = new DateTimeFormatterBuilder().append(
0766: null,
0767: new DateTimeParser[] { time,
0768: dateOptionalTimeParser().getParser() })
0769: .toFormatter();
0770: }
0771: return dtp;
0772: }
0773:
0774: /**
0775: * Returns a generic ISO datetime parser where the date is mandatory and
0776: * the time is optional. This parser can parse zoned datetimes.
0777: * It accepts formats described by the following syntax:
0778: * <pre>
0779: * date-opt-time = date-element ['T' [time-element] [offset]]
0780: * date-element = std-date-element | ord-date-element | week-date-element
0781: * std-date-element = yyyy ['-' MM ['-' dd]]
0782: * ord-date-element = yyyy ['-' DDD]
0783: * week-date-element = xxxx '-W' ww ['-' e]
0784: * time-element = HH [minute-element] | [fraction]
0785: * minute-element = ':' mm [second-element] | [fraction]
0786: * second-element = ':' ss [fraction]
0787: * fraction = ('.' | ',') digit+
0788: * </pre>
0789: * @since 1.3
0790: */
0791: public static DateTimeFormatter dateOptionalTimeParser() {
0792: if (dotp == null) {
0793: DateTimeParser timeOrOffset = new DateTimeFormatterBuilder()
0794: .appendLiteral('T').appendOptional(
0795: timeElementParser().getParser())
0796: .appendOptional(offsetElement().getParser())
0797: .toParser();
0798: dotp = new DateTimeFormatterBuilder().append(
0799: dateElementParser()).appendOptional(timeOrOffset)
0800: .toFormatter();
0801: }
0802: return dotp;
0803: }
0804:
0805: /**
0806: * Returns a generic ISO datetime parser where the date is mandatory and
0807: * the time is optional. This parser only parses local datetimes.
0808: * This parser is initialised with the local (UTC) time zone.
0809: * <p>
0810: * It accepts formats described by the following syntax:
0811: * <pre>
0812: * datetime = date-element ['T' time-element]
0813: * date-element = std-date-element | ord-date-element | week-date-element
0814: * std-date-element = yyyy ['-' MM ['-' dd]]
0815: * ord-date-element = yyyy ['-' DDD]
0816: * week-date-element = xxxx '-W' ww ['-' e]
0817: * time-element = HH [minute-element] | [fraction]
0818: * minute-element = ':' mm [second-element] | [fraction]
0819: * second-element = ':' ss [fraction]
0820: * fraction = ('.' | ',') digit+
0821: * </pre>
0822: * @since 1.3
0823: */
0824: public static DateTimeFormatter localDateOptionalTimeParser() {
0825: if (ldotp == null) {
0826: DateTimeParser time = new DateTimeFormatterBuilder()
0827: .appendLiteral('T').append(timeElementParser())
0828: .toParser();
0829: ldotp = new DateTimeFormatterBuilder().append(
0830: dateElementParser()).appendOptional(time)
0831: .toFormatter().withZone(DateTimeZone.UTC);
0832: }
0833: return ldotp;
0834: }
0835:
0836: //-----------------------------------------------------------------------
0837: /**
0838: * Returns a formatter for a full date as four digit year, two digit month
0839: * of year, and two digit day of month (yyyy-MM-dd).
0840: *
0841: * @return a formatter for yyyy-MM-dd
0842: */
0843: public static DateTimeFormatter date() {
0844: return yearMonthDay();
0845: }
0846:
0847: /**
0848: * Returns a formatter for a two digit hour of day, two digit minute of
0849: * hour, two digit second of minute, three digit fraction of second, and
0850: * time zone offset (HH:mm:ss.SSSZ).
0851: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0852: *
0853: * @return a formatter for HH:mm:ss.SSSZ
0854: */
0855: public static DateTimeFormatter time() {
0856: if (t == null) {
0857: t = new DateTimeFormatterBuilder().append(
0858: hourMinuteSecondMillis()).append(offsetElement())
0859: .toFormatter();
0860: }
0861: return t;
0862: }
0863:
0864: /**
0865: * Returns a formatter for a two digit hour of day, two digit minute of
0866: * hour, two digit second of minute, and time zone offset (HH:mm:ssZ).
0867: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0868: *
0869: * @return a formatter for HH:mm:ssZ
0870: */
0871: public static DateTimeFormatter timeNoMillis() {
0872: if (tx == null) {
0873: tx = new DateTimeFormatterBuilder().append(
0874: hourMinuteSecond()).append(offsetElement())
0875: .toFormatter();
0876: }
0877: return tx;
0878: }
0879:
0880: /**
0881: * Returns a formatter for a two digit hour of day, two digit minute of
0882: * hour, two digit second of minute, three digit fraction of second, and
0883: * time zone offset prefixed by 'T' ('T'HH:mm:ss.SSSZ).
0884: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0885: *
0886: * @return a formatter for 'T'HH:mm:ss.SSSZ
0887: */
0888: public static DateTimeFormatter tTime() {
0889: if (tt == null) {
0890: tt = new DateTimeFormatterBuilder().append(
0891: literalTElement()).append(time()).toFormatter();
0892: }
0893: return tt;
0894: }
0895:
0896: /**
0897: * Returns a formatter for a two digit hour of day, two digit minute of
0898: * hour, two digit second of minute, and time zone offset prefixed
0899: * by 'T' ('T'HH:mm:ssZ).
0900: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0901: *
0902: * @return a formatter for 'T'HH:mm:ssZ
0903: */
0904: public static DateTimeFormatter tTimeNoMillis() {
0905: if (ttx == null) {
0906: ttx = new DateTimeFormatterBuilder().append(
0907: literalTElement()).append(timeNoMillis())
0908: .toFormatter();
0909: }
0910: return ttx;
0911: }
0912:
0913: /**
0914: * Returns a formatter that combines a full date and time, separated by a 'T'
0915: * (yyyy-MM-dd'T'HH:mm:ss.SSSZ).
0916: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0917: *
0918: * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSSZ
0919: */
0920: public static DateTimeFormatter dateTime() {
0921: if (dt == null) {
0922: dt = new DateTimeFormatterBuilder().append(date()).append(
0923: tTime()).toFormatter();
0924: }
0925: return dt;
0926: }
0927:
0928: /**
0929: * Returns a formatter that combines a full date and time without millis,
0930: * separated by a 'T' (yyyy-MM-dd'T'HH:mm:ssZ).
0931: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0932: *
0933: * @return a formatter for yyyy-MM-dd'T'HH:mm:ssZ
0934: */
0935: public static DateTimeFormatter dateTimeNoMillis() {
0936: if (dtx == null) {
0937: dtx = new DateTimeFormatterBuilder().append(date()).append(
0938: tTimeNoMillis()).toFormatter();
0939: }
0940: return dtx;
0941: }
0942:
0943: /**
0944: * Returns a formatter for a full ordinal date, using a four
0945: * digit year and three digit dayOfYear (yyyy-DDD).
0946: *
0947: * @return a formatter for yyyy-DDD
0948: * @since 1.1
0949: */
0950: public static DateTimeFormatter ordinalDate() {
0951: if (od == null) {
0952: od = new DateTimeFormatterBuilder().append(yearElement())
0953: .append(dayOfYearElement()).toFormatter();
0954: }
0955: return od;
0956: }
0957:
0958: /**
0959: * Returns a formatter for a full ordinal date and time, using a four
0960: * digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ss.SSSZ).
0961: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0962: *
0963: * @return a formatter for yyyy-DDD'T'HH:mm:ss.SSSZ
0964: * @since 1.1
0965: */
0966: public static DateTimeFormatter ordinalDateTime() {
0967: if (odt == null) {
0968: odt = new DateTimeFormatterBuilder().append(ordinalDate())
0969: .append(tTime()).toFormatter();
0970: }
0971: return odt;
0972: }
0973:
0974: /**
0975: * Returns a formatter for a full ordinal date and time without millis,
0976: * using a four digit year and three digit dayOfYear (yyyy-DDD'T'HH:mm:ssZ).
0977: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
0978: *
0979: * @return a formatter for yyyy-DDD'T'HH:mm:ssZ
0980: * @since 1.1
0981: */
0982: public static DateTimeFormatter ordinalDateTimeNoMillis() {
0983: if (odtx == null) {
0984: odtx = new DateTimeFormatterBuilder().append(ordinalDate())
0985: .append(tTimeNoMillis()).toFormatter();
0986: }
0987: return odtx;
0988: }
0989:
0990: /**
0991: * Returns a formatter for a full date as four digit weekyear, two digit
0992: * week of weekyear, and one digit day of week (xxxx-'W'ww-e).
0993: *
0994: * @return a formatter for xxxx-'W'ww-e
0995: */
0996: public static DateTimeFormatter weekDate() {
0997: return weekyearWeekDay();
0998: }
0999:
1000: /**
1001: * Returns a formatter that combines a full weekyear date and time,
1002: * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ss.SSSZ).
1003: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1004: *
1005: * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ss.SSSZ
1006: */
1007: public static DateTimeFormatter weekDateTime() {
1008: if (wdt == null) {
1009: wdt = new DateTimeFormatterBuilder().append(weekDate())
1010: .append(tTime()).toFormatter();
1011: }
1012: return wdt;
1013: }
1014:
1015: /**
1016: * Returns a formatter that combines a full weekyear date and time without millis,
1017: * separated by a 'T' (xxxx-'W'ww-e'T'HH:mm:ssZ).
1018: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1019: *
1020: * @return a formatter for xxxx-'W'ww-e'T'HH:mm:ssZ
1021: */
1022: public static DateTimeFormatter weekDateTimeNoMillis() {
1023: if (wdtx == null) {
1024: wdtx = new DateTimeFormatterBuilder().append(weekDate())
1025: .append(tTimeNoMillis()).toFormatter();
1026: }
1027: return wdtx;
1028: }
1029:
1030: //-----------------------------------------------------------------------
1031: /**
1032: * Returns a basic formatter for a full date as four digit year, two digit
1033: * month of year, and two digit day of month (yyyyMMdd).
1034: *
1035: * @return a formatter for yyyyMMdd
1036: */
1037: public static DateTimeFormatter basicDate() {
1038: if (bd == null) {
1039: bd = new DateTimeFormatterBuilder().appendYear(4, 4)
1040: .appendMonthOfYear(2).appendDayOfMonth(2)
1041: .toFormatter();
1042: }
1043: return bd;
1044: }
1045:
1046: /**
1047: * Returns a basic formatter for a two digit hour of day, two digit minute
1048: * of hour, two digit second of minute, three digit millis, and time zone
1049: * offset (HHmmss.SSSZ).
1050: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1051: *
1052: * @return a formatter for HHmmss.SSSZ
1053: */
1054: public static DateTimeFormatter basicTime() {
1055: if (bt == null) {
1056: bt = new DateTimeFormatterBuilder().appendHourOfDay(2)
1057: .appendMinuteOfHour(2).appendSecondOfMinute(2)
1058: .appendLiteral('.').appendMillisOfSecond(3)
1059: .appendTimeZoneOffset("Z", false, 2, 2)
1060: .toFormatter();
1061: }
1062: return bt;
1063: }
1064:
1065: /**
1066: * Returns a basic formatter for a two digit hour of day, two digit minute
1067: * of hour, two digit second of minute, and time zone offset (HHmmssZ).
1068: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1069: *
1070: * @return a formatter for HHmmssZ
1071: */
1072: public static DateTimeFormatter basicTimeNoMillis() {
1073: if (btx == null) {
1074: btx = new DateTimeFormatterBuilder().appendHourOfDay(2)
1075: .appendMinuteOfHour(2).appendSecondOfMinute(2)
1076: .appendTimeZoneOffset("Z", false, 2, 2)
1077: .toFormatter();
1078: }
1079: return btx;
1080: }
1081:
1082: /**
1083: * Returns a basic formatter for a two digit hour of day, two digit minute
1084: * of hour, two digit second of minute, three digit millis, and time zone
1085: * offset prefixed by 'T' ('T'HHmmss.SSSZ).
1086: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1087: *
1088: * @return a formatter for 'T'HHmmss.SSSZ
1089: */
1090: public static DateTimeFormatter basicTTime() {
1091: if (btt == null) {
1092: btt = new DateTimeFormatterBuilder().append(
1093: literalTElement()).append(basicTime())
1094: .toFormatter();
1095: }
1096: return btt;
1097: }
1098:
1099: /**
1100: * Returns a basic formatter for a two digit hour of day, two digit minute
1101: * of hour, two digit second of minute, and time zone offset prefixed by 'T'
1102: * ('T'HHmmssZ).
1103: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1104: *
1105: * @return a formatter for 'T'HHmmssZ
1106: */
1107: public static DateTimeFormatter basicTTimeNoMillis() {
1108: if (bttx == null) {
1109: bttx = new DateTimeFormatterBuilder().append(
1110: literalTElement()).append(basicTimeNoMillis())
1111: .toFormatter();
1112: }
1113: return bttx;
1114: }
1115:
1116: /**
1117: * Returns a basic formatter that combines a basic date and time, separated
1118: * by a 'T' (yyyyMMdd'T'HHmmss.SSSZ).
1119: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1120: *
1121: * @return a formatter for yyyyMMdd'T'HHmmss.SSSZ
1122: */
1123: public static DateTimeFormatter basicDateTime() {
1124: if (bdt == null) {
1125: bdt = new DateTimeFormatterBuilder().append(basicDate())
1126: .append(basicTTime()).toFormatter();
1127: }
1128: return bdt;
1129: }
1130:
1131: /**
1132: * Returns a basic formatter that combines a basic date and time without millis,
1133: * separated by a 'T' (yyyyMMdd'T'HHmmssZ).
1134: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1135: *
1136: * @return a formatter for yyyyMMdd'T'HHmmssZ
1137: */
1138: public static DateTimeFormatter basicDateTimeNoMillis() {
1139: if (bdtx == null) {
1140: bdtx = new DateTimeFormatterBuilder().append(basicDate())
1141: .append(basicTTimeNoMillis()).toFormatter();
1142: }
1143: return bdtx;
1144: }
1145:
1146: /**
1147: * Returns a formatter for a full ordinal date, using a four
1148: * digit year and three digit dayOfYear (yyyyDDD).
1149: *
1150: * @return a formatter for yyyyDDD
1151: * @since 1.1
1152: */
1153: public static DateTimeFormatter basicOrdinalDate() {
1154: if (bod == null) {
1155: bod = new DateTimeFormatterBuilder().appendYear(4, 4)
1156: .appendDayOfYear(3).toFormatter();
1157: }
1158: return bod;
1159: }
1160:
1161: /**
1162: * Returns a formatter for a full ordinal date and time, using a four
1163: * digit year and three digit dayOfYear (yyyyDDD'T'HHmmss.SSSZ).
1164: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1165: *
1166: * @return a formatter for yyyyDDD'T'HHmmss.SSSZ
1167: * @since 1.1
1168: */
1169: public static DateTimeFormatter basicOrdinalDateTime() {
1170: if (bodt == null) {
1171: bodt = new DateTimeFormatterBuilder().append(
1172: basicOrdinalDate()).append(basicTTime())
1173: .toFormatter();
1174: }
1175: return bodt;
1176: }
1177:
1178: /**
1179: * Returns a formatter for a full ordinal date and time without millis,
1180: * using a four digit year and three digit dayOfYear (yyyyDDD'T'HHmmssZ).
1181: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1182: *
1183: * @return a formatter for yyyyDDD'T'HHmmssZ
1184: * @since 1.1
1185: */
1186: public static DateTimeFormatter basicOrdinalDateTimeNoMillis() {
1187: if (bodtx == null) {
1188: bodtx = new DateTimeFormatterBuilder().append(
1189: basicOrdinalDate()).append(basicTTimeNoMillis())
1190: .toFormatter();
1191: }
1192: return bodtx;
1193: }
1194:
1195: /**
1196: * Returns a basic formatter for a full date as four digit weekyear, two
1197: * digit week of weekyear, and one digit day of week (xxxx'W'wwe).
1198: *
1199: * @return a formatter for xxxx'W'wwe
1200: */
1201: public static DateTimeFormatter basicWeekDate() {
1202: if (bwd == null) {
1203: bwd = new DateTimeFormatterBuilder().appendWeekyear(4, 4)
1204: .appendLiteral('W').appendWeekOfWeekyear(2)
1205: .appendDayOfWeek(1).toFormatter();
1206: }
1207: return bwd;
1208: }
1209:
1210: /**
1211: * Returns a basic formatter that combines a basic weekyear date and time,
1212: * separated by a 'T' (xxxx'W'wwe'T'HHmmss.SSSZ).
1213: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1214: *
1215: * @return a formatter for xxxx'W'wwe'T'HHmmss.SSSZ
1216: */
1217: public static DateTimeFormatter basicWeekDateTime() {
1218: if (bwdt == null) {
1219: bwdt = new DateTimeFormatterBuilder().append(
1220: basicWeekDate()).append(basicTTime()).toFormatter();
1221: }
1222: return bwdt;
1223: }
1224:
1225: /**
1226: * Returns a basic formatter that combines a basic weekyear date and time
1227: * without millis, separated by a 'T' (xxxx'W'wwe'T'HHmmssZ).
1228: * The time zone offset is 'Z' for zero, and of the form '\u00b1HH:mm' for non-zero.
1229: *
1230: * @return a formatter for xxxx'W'wwe'T'HHmmssZ
1231: */
1232: public static DateTimeFormatter basicWeekDateTimeNoMillis() {
1233: if (bwdtx == null) {
1234: bwdtx = new DateTimeFormatterBuilder().append(
1235: basicWeekDate()).append(basicTTimeNoMillis())
1236: .toFormatter();
1237: }
1238: return bwdtx;
1239: }
1240:
1241: //-----------------------------------------------------------------------
1242: /**
1243: * Returns a formatter for a four digit year. (yyyy)
1244: *
1245: * @return a formatter for yyyy
1246: */
1247: public static DateTimeFormatter year() {
1248: return yearElement();
1249: }
1250:
1251: /**
1252: * Returns a formatter for a four digit year and two digit month of
1253: * year. (yyyy-MM)
1254: *
1255: * @return a formatter for yyyy-MM
1256: */
1257: public static DateTimeFormatter yearMonth() {
1258: if (ym == null) {
1259: ym = new DateTimeFormatterBuilder().append(yearElement())
1260: .append(monthElement()).toFormatter();
1261: }
1262: return ym;
1263: }
1264:
1265: /**
1266: * Returns a formatter for a four digit year, two digit month of year, and
1267: * two digit day of month. (yyyy-MM-dd)
1268: *
1269: * @return a formatter for yyyy-MM-dd
1270: */
1271: public static DateTimeFormatter yearMonthDay() {
1272: if (ymd == null) {
1273: ymd = new DateTimeFormatterBuilder().append(yearElement())
1274: .append(monthElement()).append(dayOfMonthElement())
1275: .toFormatter();
1276: }
1277: return ymd;
1278: }
1279:
1280: /**
1281: * Returns a formatter for a four digit weekyear. (xxxx)
1282: *
1283: * @return a formatter for xxxx
1284: */
1285: public static DateTimeFormatter weekyear() {
1286: return weekyearElement();
1287: }
1288:
1289: /**
1290: * Returns a formatter for a four digit weekyear and two digit week of
1291: * weekyear. (xxxx-'W'ww)
1292: *
1293: * @return a formatter for xxxx-'W'ww
1294: */
1295: public static DateTimeFormatter weekyearWeek() {
1296: if (ww == null) {
1297: ww = new DateTimeFormatterBuilder().append(
1298: weekyearElement()).append(weekElement())
1299: .toFormatter();
1300: }
1301: return ww;
1302: }
1303:
1304: /**
1305: * Returns a formatter for a four digit weekyear, two digit week of
1306: * weekyear, and one digit day of week. (xxxx-'W'ww-e)
1307: *
1308: * @return a formatter for xxxx-'W'ww-e
1309: */
1310: public static DateTimeFormatter weekyearWeekDay() {
1311: if (wwd == null) {
1312: wwd = new DateTimeFormatterBuilder().append(
1313: weekyearElement()).append(weekElement()).append(
1314: dayOfWeekElement()).toFormatter();
1315: }
1316: return wwd;
1317: }
1318:
1319: /**
1320: * Returns a formatter for a two digit hour of day. (HH)
1321: *
1322: * @return a formatter for HH
1323: */
1324: public static DateTimeFormatter hour() {
1325: return hourElement();
1326: }
1327:
1328: /**
1329: * Returns a formatter for a two digit hour of day and two digit minute of
1330: * hour. (HH:mm)
1331: *
1332: * @return a formatter for HH:mm
1333: */
1334: public static DateTimeFormatter hourMinute() {
1335: if (hm == null) {
1336: hm = new DateTimeFormatterBuilder().append(hourElement())
1337: .append(minuteElement()).toFormatter();
1338: }
1339: return hm;
1340: }
1341:
1342: /**
1343: * Returns a formatter for a two digit hour of day, two digit minute of
1344: * hour, and two digit second of minute. (HH:mm:ss)
1345: *
1346: * @return a formatter for HH:mm:ss
1347: */
1348: public static DateTimeFormatter hourMinuteSecond() {
1349: if (hms == null) {
1350: hms = new DateTimeFormatterBuilder().append(hourElement())
1351: .append(minuteElement()).append(secondElement())
1352: .toFormatter();
1353: }
1354: return hms;
1355: }
1356:
1357: /**
1358: * Returns a formatter for a two digit hour of day, two digit minute of
1359: * hour, two digit second of minute, and three digit fraction of
1360: * second. (HH:mm:ss.SSS)
1361: *
1362: * @return a formatter for HH:mm:ss.SSS
1363: */
1364: public static DateTimeFormatter hourMinuteSecondMillis() {
1365: if (hmsl == null) {
1366: hmsl = new DateTimeFormatterBuilder().append(hourElement())
1367: .append(minuteElement()).append(secondElement())
1368: .append(millisElement()).toFormatter();
1369: }
1370: return hmsl;
1371: }
1372:
1373: /**
1374: * Returns a formatter for a two digit hour of day, two digit minute of
1375: * hour, two digit second of minute, and three digit fraction of
1376: * second. (HH:mm:ss.SSS)
1377: *
1378: * @return a formatter for HH:mm:ss.SSS
1379: */
1380: public static DateTimeFormatter hourMinuteSecondFraction() {
1381: if (hmsf == null) {
1382: hmsf = new DateTimeFormatterBuilder().append(hourElement())
1383: .append(minuteElement()).append(secondElement())
1384: .append(fractionElement()).toFormatter();
1385: }
1386: return hmsf;
1387: }
1388:
1389: /**
1390: * Returns a formatter that combines a full date and two digit hour of
1391: * day. (yyyy-MM-dd'T'HH)
1392: *
1393: * @return a formatter for yyyy-MM-dd'T'HH
1394: */
1395: public static DateTimeFormatter dateHour() {
1396: if (dh == null) {
1397: dh = new DateTimeFormatterBuilder().append(date()).append(
1398: literalTElement()).append(hour()).toFormatter();
1399: }
1400: return dh;
1401: }
1402:
1403: /**
1404: * Returns a formatter that combines a full date, two digit hour of day,
1405: * and two digit minute of hour. (yyyy-MM-dd'T'HH:mm)
1406: *
1407: * @return a formatter for yyyy-MM-dd'T'HH:mm
1408: */
1409: public static DateTimeFormatter dateHourMinute() {
1410: if (dhm == null) {
1411: dhm = new DateTimeFormatterBuilder().append(date()).append(
1412: literalTElement()).append(hourMinute())
1413: .toFormatter();
1414: }
1415: return dhm;
1416: }
1417:
1418: /**
1419: * Returns a formatter that combines a full date, two digit hour of day,
1420: * two digit minute of hour, and two digit second of
1421: * minute. (yyyy-MM-dd'T'HH:mm:ss)
1422: *
1423: * @return a formatter for yyyy-MM-dd'T'HH:mm:ss
1424: */
1425: public static DateTimeFormatter dateHourMinuteSecond() {
1426: if (dhms == null) {
1427: dhms = new DateTimeFormatterBuilder().append(date())
1428: .append(literalTElement()).append(
1429: hourMinuteSecond()).toFormatter();
1430: }
1431: return dhms;
1432: }
1433:
1434: /**
1435: * Returns a formatter that combines a full date, two digit hour of day,
1436: * two digit minute of hour, two digit second of minute, and three digit
1437: * fraction of second. (yyyy-MM-dd'T'HH:mm:ss.SSS)
1438: *
1439: * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS
1440: */
1441: public static DateTimeFormatter dateHourMinuteSecondMillis() {
1442: if (dhmsl == null) {
1443: dhmsl = new DateTimeFormatterBuilder().append(date())
1444: .append(literalTElement()).append(
1445: hourMinuteSecondMillis()).toFormatter();
1446: }
1447: return dhmsl;
1448: }
1449:
1450: /**
1451: * Returns a formatter that combines a full date, two digit hour of day,
1452: * two digit minute of hour, two digit second of minute, and three digit
1453: * fraction of second. (yyyy-MM-dd'T'HH:mm:ss.SSS)
1454: *
1455: * @return a formatter for yyyy-MM-dd'T'HH:mm:ss.SSS
1456: */
1457: public static DateTimeFormatter dateHourMinuteSecondFraction() {
1458: if (dhmsf == null) {
1459: dhmsf = new DateTimeFormatterBuilder().append(date())
1460: .append(literalTElement()).append(
1461: hourMinuteSecondFraction()).toFormatter();
1462: }
1463: return dhmsf;
1464: }
1465:
1466: //-----------------------------------------------------------------------
1467: private static DateTimeFormatter yearElement() {
1468: if (ye == null) {
1469: ye = new DateTimeFormatterBuilder().appendYear(4, 9)
1470: .toFormatter();
1471: }
1472: return ye;
1473: }
1474:
1475: private static DateTimeFormatter monthElement() {
1476: if (mye == null) {
1477: mye = new DateTimeFormatterBuilder().appendLiteral('-')
1478: .appendMonthOfYear(2).toFormatter();
1479: }
1480: return mye;
1481: }
1482:
1483: private static DateTimeFormatter dayOfMonthElement() {
1484: if (dme == null) {
1485: dme = new DateTimeFormatterBuilder().appendLiteral('-')
1486: .appendDayOfMonth(2).toFormatter();
1487: }
1488: return dme;
1489: }
1490:
1491: private static DateTimeFormatter weekyearElement() {
1492: if (we == null) {
1493: we = new DateTimeFormatterBuilder().appendWeekyear(4, 9)
1494: .toFormatter();
1495: }
1496: return we;
1497: }
1498:
1499: private static DateTimeFormatter weekElement() {
1500: if (wwe == null) {
1501: wwe = new DateTimeFormatterBuilder().appendLiteral("-W")
1502: .appendWeekOfWeekyear(2).toFormatter();
1503: }
1504: return wwe;
1505: }
1506:
1507: private static DateTimeFormatter dayOfWeekElement() {
1508: if (dwe == null) {
1509: dwe = new DateTimeFormatterBuilder().appendLiteral('-')
1510: .appendDayOfWeek(1).toFormatter();
1511: }
1512: return dwe;
1513: }
1514:
1515: private static DateTimeFormatter dayOfYearElement() {
1516: if (dye == null) {
1517: dye = new DateTimeFormatterBuilder().appendLiteral('-')
1518: .appendDayOfYear(3).toFormatter();
1519: }
1520: return dye;
1521: }
1522:
1523: private static DateTimeFormatter literalTElement() {
1524: if (lte == null) {
1525: lte = new DateTimeFormatterBuilder().appendLiteral('T')
1526: .toFormatter();
1527: }
1528: return lte;
1529: }
1530:
1531: private static DateTimeFormatter hourElement() {
1532: if (hde == null) {
1533: hde = new DateTimeFormatterBuilder().appendHourOfDay(2)
1534: .toFormatter();
1535: }
1536: return hde;
1537: }
1538:
1539: private static DateTimeFormatter minuteElement() {
1540: if (mhe == null) {
1541: mhe = new DateTimeFormatterBuilder().appendLiteral(':')
1542: .appendMinuteOfHour(2).toFormatter();
1543: }
1544: return mhe;
1545: }
1546:
1547: private static DateTimeFormatter secondElement() {
1548: if (sme == null) {
1549: sme = new DateTimeFormatterBuilder().appendLiteral(':')
1550: .appendSecondOfMinute(2).toFormatter();
1551: }
1552: return sme;
1553: }
1554:
1555: private static DateTimeFormatter millisElement() {
1556: if (lse == null) {
1557: lse = new DateTimeFormatterBuilder().appendLiteral('.')
1558: .appendMillisOfSecond(3).toFormatter();
1559: }
1560: return lse;
1561: }
1562:
1563: private static DateTimeFormatter fractionElement() {
1564: if (fse == null) {
1565: fse = new DateTimeFormatterBuilder().appendLiteral('.')
1566: // Support parsing up to nanosecond precision even though
1567: // those extra digits will be dropped.
1568: .appendFractionOfSecond(3, 9).toFormatter();
1569: }
1570: return fse;
1571: }
1572:
1573: private static DateTimeFormatter offsetElement() {
1574: if (ze == null) {
1575: ze = new DateTimeFormatterBuilder().appendTimeZoneOffset(
1576: "Z", true, 2, 4).toFormatter();
1577: }
1578: return ze;
1579: }
1580:
1581: }
|