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

com.adobe.xfa.ut.LcTime Maven / Gradle / Ivy

There is a newer version: 2024.9.17689.20240905T073330Z-240800
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */

package com.adobe.xfa.ut;

import java.util.Calendar;
import java.util.TimeZone;

/**
 * The LcTime class defines objects in support
 * of XFA time picture patterns.
 * 
 * 

* The time is internally represented as the number of milliseconds from the * epoch, which is midnight 00:00:00 GMT, i.e., time 1 is midnight GMT. * *

* Time picture patterns are used to parse and format time strings. * Here are the metasymbols that form valid time picture patterns: *

*
h *
a one or two digit (1-12) hour of AM/PM. *
hh *
a two digit (01-12) hour of AM/PM. *
k *
a one or two digit (0-11) hour of AM/PM. *
kk *
a two digit (00-11) hour of AM/PM. *
H *
a one or two digit (0-23) hour of day. *
HH *
a two digit (00-23) hour of day. *
K *
a one or two digit (1-24) hour of day. *
KK *
a two digit (01-24) hour of day. *
M *
a one or two digit (0-59) minute of hour. *
MM *
a two digit (00-59) minute of hour. *
S *
a one or two digit (0-59) second of minute. *
SS *
a two digit (00-59) second of minute. *
FFF *
a three digit (000-999) thousandth of second. *
A *
a meridiem name (AM/PM) of the ambient locale. *
Z *
an abbreviated time zone name of the ambient locale. *
z *
an ISO8601 time zone format: Z, +HH[MM], -HH[MM]. *
zz *
an alternate ISO8601 time zone format: Z, +HH[:MM], -HH[:MM]. *
* * Here's a snippet of code illustrating the use of {@link LcTime} to reformat a * time string * *

 * 
 *       import com.adobe.xfa.ut.LcTime;            // for defn of LcTime.
 *       ...
 *       String loc = "en_ca"
 *       String fmt = LcTime.DEFAULT_TIME_FMT;
 *       LcTime now = new LcTime(loc);
 *       now.setLocalTime();
 *       now += 2 * LcTime.MILLISPERHOUR;
 *       if (now.isValid())
 *           System.out.println(now.format("h:MM:SS:FFF A Z"));
 *  
 * 
* * @author Mike P. Tardif * * @exclude from published api. */ public class LcTime { /** * An inner class to represent locale sensitve * time symbols. */ private static class Symbols { private final String meridiemName[] = new String[2]; private char zeroDigit; } /** * An inner static class to represent each locale's timezone info. */ private static class TimeZoneInfo { private final String isoName; // ISO locale name private final int offset; // minutes westward of Greenwich private final int dstflg; // daylight savings is applicable private final String stdName; // abbreviated standard time zone name private final String dstName; // abbreviated daylight savings time zone name private TimeZoneInfo(String iso, int off, int flg, String std, String dst) { isoName = iso; offset = off; dstflg = flg; stdName = std; dstName = dst; } } /** * The number of milliseconds from the epoch. */ protected int mMillis; /** * The local time zone adjustment in milliseconds westward of Greenwich. */ protected int mAdjustment; /** * The effect of daylight savings time. */ private boolean mDaylightSavingsTime; /** * The parsed hour of the day. */ protected int mHourOfDay; /** * The parsed hour of the meridiem. */ protected int mHourOfMeriDiem; /** * The locale. */ protected LcLocale mLocale; /** * The parsed meridiem. */ protected int mMeriDiem; /** * The parsed minute of the hour. */ protected int mMinuteOfHour; /** * The parsed second of the minute. */ protected int mSecondOfMinute; /** * The locale sensitive time symbols. */ private Symbols mSymbols; /** * The parsed thousandth of the second. */ protected int mThousandthOfSecond; /** * The parsed time zone offset in milliseconds westward of Greenwich. */ protected int mTimeZone; /** * The have-parsed-a-time-zone flag. */ protected boolean mTimeZoneSeen; /** * The validity of this time. */ protected boolean mValid; /** * Each locale's timezone info. */ private static final TimeZoneInfo[] mTimeZoneName = { new TimeZoneInfo(LcLocale.English_US, -600, 1, "HAST", "HADT"), // Hawaii-Aleutian Standard/Daylight Time new TimeZoneInfo(null, -600, 0, "HAST", "HAST"), // Hawaii-Aleutian Standard Time new TimeZoneInfo(null, -540, 1, "AKST", "AKDT"), // Alaska Standard/Daylight Time new TimeZoneInfo(null, -480, 1, "PST", "PDT"), // Pacific Standard/Daylight Time new TimeZoneInfo(null, -420, 1, "MST", "MDT"), // Mountain Standard/Daylight Time new TimeZoneInfo(null, -420, 0, "PNT", "MST"), // Phoenix/Mountain Standard Time new TimeZoneInfo(null, -360, 1, "CST", "CDT"), // Central Standard/Daylight Time new TimeZoneInfo(null, -300, 1, "EST", "EDT"), // Eastern Standard/Daylight Time new TimeZoneInfo(null, -300, 0, "IET", "EST"), // Indiana/Eastern Standard Time new TimeZoneInfo(null, -240, 1, "AST", "ADT"), // Atlantic Standard/Daylight Time new TimeZoneInfo(null, -210, 1, "NST", "NDT"), // Newfoundland Standard/Daylight Time new TimeZoneInfo(LcLocale.C, 0, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_UAE, 240, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Bahrain, 180, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Algeria, 60, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Egypt, 120, 1, null, null), new TimeZoneInfo(LcLocale.Arabic_Iraq, 180, 1, null, null), new TimeZoneInfo(LcLocale.Arabic_Jordan, 120, 1, null, null), new TimeZoneInfo(LcLocale.Arabic_Kuwait, 180, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Lebanon, 120, 1, null, null), new TimeZoneInfo(LcLocale.Arabic_Libya, 120, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Morocco, 0, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Oman, 240, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Qatar, 180, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_SaudiArabia, 180, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Sudan, 180, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Syria, 120, 1, null, null), new TimeZoneInfo(LcLocale.Arabic_Tunisia, 60, 0, null, null), new TimeZoneInfo(LcLocale.Arabic_Yemen, 180, 0, null, null), new TimeZoneInfo(LcLocale.Azerbaijani_Cyrillic_Azerbaijan, 240, 1, null, null), new TimeZoneInfo(LcLocale.Azerbaijani_Latin_Azerbaijan, 240, 1, null, null), new TimeZoneInfo(LcLocale.Byelorussian_Belarus, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Bulgarian_Bulgaria, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Bosnian_BosniaHerzegovina, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Catalan_Spain, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Czech_CzechRepublic, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Danish_Denmark, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.German_Austria, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(null, 60, 1, "MEZ", "MESZ"), // Mitteleuropaische (Sommer) Zeit new TimeZoneInfo(LcLocale.German_Belgium, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.German_Switzerland, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(null, 60, 1, "MEZ", "MESZ"), // Mitteleuropaische (Sommer) Zeit new TimeZoneInfo(LcLocale.German_Germany, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(null, 60, 1, "MEZ", "MESZ"), // Mitteleuropaische (Sommer) Zeit new TimeZoneInfo(LcLocale.German_Liechtenstein, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.German_Luxembourg, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(null, 60, 1, "MEZ", "MESZ"), // Mitteleuropaische (Sommer) Zeit new TimeZoneInfo(LcLocale.Greek_Greece, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.English_Australia, 420, 0, "CXT", "CXT"), // Christmas Island (Standard) Time new TimeZoneInfo(null, 480, 0, "AWST", "AWST"), // Western Standard Time new TimeZoneInfo(null, 570, 1, "ACST", "ACDT"), // Central Standard/Daylight Time new TimeZoneInfo(null, 570, 0, "ACST", "ACST"), // Central Standard Time new TimeZoneInfo(null, 600, 1, "AEST", "AEDT"), // Eastern Standard/Daylight Time new TimeZoneInfo(null, 600, 0, "AEST", "AEST"), // Eastern Standard Time new TimeZoneInfo(null, 690, 0, "NFT", "NFT"), // Norfolk Island Standard Time new TimeZoneInfo(LcLocale.English_Belgium, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.English_Canada, -480, 1, "PST", "PDT"), // Pacific Daylight Time new TimeZoneInfo(null, -420, 1, "MST", "MDT"), // Mountain Daylight Time new TimeZoneInfo(null, -360, 1, "CST", "CDT"), // Central Daylight Time new TimeZoneInfo(null, -300, 1, "EST", "EDT"), // Eastern Daylight Time new TimeZoneInfo(null, -240, 1, "AST", "ADT"), // Atlantic Daylight Time new TimeZoneInfo(null, -210, 1, "NST", "NDT"), // Newfoundland Daylight Time new TimeZoneInfo(LcLocale.English_UK, 0, 1, null, "BST"), // British Summer Time new TimeZoneInfo(LcLocale.English_HongKong, 480, 0, null, null), new TimeZoneInfo(LcLocale.English_Ireland, 0, 1, null, "IST"), // Irish Summer Time new TimeZoneInfo(LcLocale.English_India, 330, 0, null, null), new TimeZoneInfo(LcLocale.English_NewZealand, 720, 0, null, null), new TimeZoneInfo(LcLocale.English_Philippines, 480, 0, null, null), new TimeZoneInfo(LcLocale.English_Singapore, 480, 0, "SST", null), new TimeZoneInfo(LcLocale.English_VirginIslands, -240, 1, null, null), new TimeZoneInfo(LcLocale.English_SouthAfrica, 120, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Argentina, -180, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Bolivia, -240, 0, "AST", "AST"), // Andes Standard Time new TimeZoneInfo(LcLocale.Spanish_Chile, -240, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Colombia, -300, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_CostaRica, -360, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_DominicanRepublic, -240, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Ecuador, -300, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Spain, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Spanish_Guatemala, -360, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Honduras, -360, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Mexico, -480, 1, "PST", "PDT"), // Hora del Noroeste new TimeZoneInfo(null, -420, 1, "MST", "MDT"), // Hora del Pacifico new TimeZoneInfo(null, -420, 0, "MST", "MST"), // Hora de Sonora new TimeZoneInfo(null, -360, 1, "CST", "CDT"), // Hora del Centro new TimeZoneInfo(LcLocale.Spanish_Nicaragua, -360, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Panama, -300, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Peru, -300, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_PuertoRico, -300, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Paraguay, -240, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_ElSalvador, -360, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_US, -600, 1, "HAST", "HADT"), // Hawaii-Aleutian Standard/Daylight Time new TimeZoneInfo(null, -600, 0, "HAST", "HAST"), // Hawaii-Aleutian Standard Time new TimeZoneInfo(null, -540, 1, "AKST", "AKDT"), // Alaska Standard/Daylight Time new TimeZoneInfo(null, -480, 1, "PST", "PDT"), // Pacific Standard/Daylight Time new TimeZoneInfo(null, -420, 1, "MST", "MDT"), // Mountain Standard/Daylight Time new TimeZoneInfo(null, -420, 0, "PNT", "MST"), // Phoenix/Mountain Standard Time new TimeZoneInfo(null, -360, 1, "CST", "CDT"), // Central Standard/Daylight Time new TimeZoneInfo(null, -300, 1, "EST", "EDT"), // Eastern Standard/Daylight Time new TimeZoneInfo(null, -300, 0, "IET", "EST"), // Indiana/Eastern Standard Time new TimeZoneInfo(null, -240, 1, "AST", "ADT"), // Atlantic Standard/Daylight Time new TimeZoneInfo(null, -210, 1, "NST", "NDT"), // Newfoundland Standard/Daylight Time new TimeZoneInfo(LcLocale.Spanish_Uruguay, -180, 0, null, null), new TimeZoneInfo(LcLocale.Spanish_Venezuela, -240, 0, null, null), new TimeZoneInfo(LcLocale.Estonian_Estonia, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Basque_Spain, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Persian_Iran, 210, 0, null, null), new TimeZoneInfo(LcLocale.Finnish_Finland, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.French_Belgium, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.French_Canada, -480, 1, "HNP", "HAP"), // Heure Normale/Avancee du Pacifique new TimeZoneInfo(null, -420, 1, "HNR", "HAR"), // Heure Normale/Avancee des Rocheuses new TimeZoneInfo(null, -360, 1, "HNC", "HAC"), // Heure Normale/Avancee du Centre new TimeZoneInfo(null, -300, 1, "HNE", "HAE"), // Heure Normale/Avancee de l'Est new TimeZoneInfo(null, -240, 1, "HNA", "HAA"), // Heure Normale/Avancee de l'Atlantique new TimeZoneInfo(null, -210, 1, "HNT", "HAT"), // Heure Normale/Avancee de Terre Neuve new TimeZoneInfo(LcLocale.French_Switzerland, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.French_France, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.French_Luxembourg, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Hebrew_Israel, 120, 1, null, null), new TimeZoneInfo(LcLocale.Hindi_India, 330, 0, null, null), new TimeZoneInfo(LcLocale.Croatian_Croatia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Hungarian_Hungary, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Armenian_Armenia, 240, 1, null, null), new TimeZoneInfo(LcLocale.Indonesian_Indonesia, 420, 0, null, null), new TimeZoneInfo(LcLocale.Icelandic_Iceland, 0, 0, null, null), new TimeZoneInfo(LcLocale.Italian_Switzerland, 60, 1, "CET", "CEST"), // Central European (DST) Time new TimeZoneInfo(LcLocale.Italian_Italy, 60, 1, "CET", "CEST"), // Central European (DST) Time new TimeZoneInfo(LcLocale.Japanese_Japan, 540, 0, "JST", "JST"), // Japanese Standard Time new TimeZoneInfo(LcLocale.Kazakh_Kazakhstan, 300, 0, null, null), new TimeZoneInfo(null, 360, 0, null, null), new TimeZoneInfo(LcLocale.Khmer_Cambodia, 420, 0, null, null), new TimeZoneInfo(LcLocale.Korean_Korea, 540, 0, "KST", "KST"), // Korean Standard Time new TimeZoneInfo(LcLocale.Lao_Laos, 420, 1, null, null), new TimeZoneInfo(LcLocale.Lithuanian_Lithuania, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Latvian_Latvia, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Macedonian_Macedonia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Malay_Malaysia, 480, 0, null, null), new TimeZoneInfo(LcLocale.Norwegian_Bokmal_Norway, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Dutch_Belgium, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Dutch_Netherlands, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Norwegian_Nynorsk_Norway, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo("no_NO", 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo("no_NO_NY", 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Polish_Poland, 120, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Portuguese_Brazil, -240, 0, null, null), // Andes Standard Time new TimeZoneInfo(null, -240, 0, null, null), // Western Standard/Daylight Time new TimeZoneInfo(null, -180, 1, null, null), // Eastern Standard/Daylight Time new TimeZoneInfo(null, -120, 0, null, null), // Fernando's de Noronha Standard Time new TimeZoneInfo(LcLocale.Portuguese_Portugal, 0, 1, "WET", "WEST"), // Western European (Summer) Time new TimeZoneInfo(LcLocale.Romanian_Moldova, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Romanian_Romania, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Russian_Moldova, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Russian_Russia, 180, 1, null, null), new TimeZoneInfo(null, 240, 1, null, null), new TimeZoneInfo(null, 300, 1, null, null), new TimeZoneInfo(null, 360, 1, null, null), new TimeZoneInfo(null, 420, 1, null, null), new TimeZoneInfo(null, 480, 1, null, null), new TimeZoneInfo(null, 540, 1, null, null), new TimeZoneInfo(null, 600, 1, null, null), new TimeZoneInfo(null, 660, 1, null, null), new TimeZoneInfo(null, 720, 1, null, null), new TimeZoneInfo(LcLocale.Russian_Ukraine, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Serbo_Croatian, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Serbo_Croatian_BosniaHerzegovina, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Serbo_Croatian_SerbiaMontenegro, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Serbo_Croatian_Croatia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Slovak_Slovakia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Slovenian_Slovenia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Albanian_Albania, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Serbian_Yugoslavia, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Serbian_Cyrillic_SerbiaMontenegro, 60, 1, null, null), new TimeZoneInfo(LcLocale.Serbian_Latin_SerbiaMontenegro, 60, 1, null, null), new TimeZoneInfo(LcLocale.Swedish_Finland, 120, 1, "EET", "EEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Swedish_Sweden, 60, 1, "CET", "CEST"), // Central European (Summer) Time new TimeZoneInfo(LcLocale.Thai_Thailand, 420, 0, null, null), new TimeZoneInfo(LcLocale.Tagalog_Philippines, 480, 0, null, null), new TimeZoneInfo(LcLocale.Turkish_Turkey, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Ukrainian_Ukraine, 120, 1, "EET", "EEST"), // Eastern European (Summer) Time new TimeZoneInfo(LcLocale.Vietnamese_Vietnam, 420, 0, null, null), new TimeZoneInfo(LcLocale.Chinese_China, 480, 0, null, null), new TimeZoneInfo(LcLocale.Chinese_HongKong, 480, 0, null, null), new TimeZoneInfo(LcLocale.Chinese_Singapore, 480, 0, null, null), new TimeZoneInfo(LcLocale.Chinese_Taiwan, 480, 0, null, null) }; /** * Default LcTime pattern string for English_US locale: h:MM:SS A. */ public static final String DEFAULT_TIME_FMT = "h:MM:SS A"; public static final int MILLISPERDAY = 24 * 60 * 60 * 1000; public static final int MILLISPERHOUR = 60 * 60 * 1000; public static final int MILLISPERMINUTE = 60 * 1000; public static final int MILLISPERSECOND = 1000; /** * ISO8601/XFA time pattern string: HHMMSS.FFFz. */ public static final String TIME_FMT1 = "HHMMSS.FFFz"; /** * Alternate ISO8601/XFA time pattern string: HH:MM:SS.FFFzz. */ public static final String TIME_FMT2 = "HH:MM:SS.FFFzz"; /** * LcTime pattern symbols: hkHKMSFAzZ. */ public static final String TIME_PICTURE_SYMBOLS = "hkHKMSFAZzt"; /** * Instantiates an LcTime object from today's Greenwich Mean time and in the * locale given. * * @param locale * a locale string. When empty, it will default to the default * locale. */ public LcTime(String locale /* = "" */) { mSymbols = new Symbols(); Calendar now = Calendar.getInstance(TimeZone.getTimeZone("GMT")); int uhr = now.get(Calendar.HOUR_OF_DAY); int min = now.get(Calendar.MINUTE); int sec = now.get(Calendar.SECOND); int millisec = now.get(Calendar.MILLISECOND); String sLocale = StringUtils.isEmpty(locale) ? LcLocale.getLocale() : locale; mLocale = new LcLocale(sLocale); if (! mLocale.isValid()) mLocale = new LcLocale(LcLocale.DEFAULT_LOCALE); setTimeSymbols(mLocale.getIsoName()); mMillis = epoch(uhr, min, sec, millisec, 0); mValid = (mMillis != 0); } /** * Instantiates an LcTime object from the number of milliseconds from the * epoch and in the locale given. The epoch is such that time 1 corresponds * to midnight, 00:00:00 GMT. * * @param millis * the number of milliseconds from epoch. * @param locale * a locale string. When empty, it will default to the default * locale. */ public LcTime(int millis, String locale /* = "" */) { mSymbols = new Symbols(); String sLocale = StringUtils.isEmpty(locale) ? LcLocale.getLocale() : locale; mLocale = new LcLocale(sLocale); if (! mLocale.isValid()) mLocale = new LcLocale(LcLocale.DEFAULT_LOCALE); setTimeSymbols(mLocale.getIsoName()); mMillis = millis % MILLISPERDAY; mValid = (mMillis != 0); } /** * Instantiates an LcTime object from the given time in the pattern given and * in the locale given. * * @param time * a time string. * @param pat * a time pattern string used to parse the given time. * @param locale * a locale string. When empty, it will default to the default * locale. */ public LcTime(String time, String pat, String locale /* = "" */) { mSymbols = new Symbols(); String sLocale = StringUtils.isEmpty(locale) ? LcLocale.getLocale() : locale; mLocale = new LcLocale(sLocale); if (! mLocale.isValid()) mLocale = new LcLocale(LcLocale.DEFAULT_LOCALE); setTimeSymbols(mLocale.getIsoName()); if (parse(time, pat)) { mMillis = epoch(mHourOfDay, mMinuteOfHour, mSecondOfMinute, mThousandthOfSecond, mTimeZone); mValid = true; } } /** * Instantiates an LcTime object from an existing LcTime object * * @param oTime * an existing LcTime object */ public LcTime(LcTime oTime) { asgn(oTime); } /** * Adds the given milliseconds to this object. * * @param millis * the number of milliseconds to add. * @return * this modified object. */ public LcTime add(int millis) { if (mValid) mMillis += millis; mMillis = mMillis % MILLISPERDAY; mValid = (mMillis != 0); return this; } /** * Assigns the given LcTime object to this object. * * @param oTime * an existing LcTime object. * @return * this object. */ public LcTime asgn(LcTime oTime) { mMillis = oTime.mMillis; mAdjustment = oTime.mAdjustment; mDaylightSavingsTime = oTime.mDaylightSavingsTime; mLocale = oTime.mLocale; mValid = oTime.mValid; mSymbols.meridiemName[0] = oTime.mSymbols.meridiemName[0]; mSymbols.meridiemName[1] = oTime.mSymbols.meridiemName[1]; mSymbols.zeroDigit = oTime.mSymbols.zeroDigit; mHourOfMeriDiem = oTime.mHourOfMeriDiem; mHourOfDay = oTime.mHourOfDay; mMinuteOfHour = oTime.mMinuteOfHour; mSecondOfMinute = oTime.mSecondOfMinute; mThousandthOfSecond = oTime.mThousandthOfSecond; mMeriDiem = oTime.mMeriDiem; mTimeZone = oTime.mTimeZone; mTimeZoneSeen = oTime.mTimeZoneSeen; return this; } /** * Calculates the number of milliseconds from the epoch given an hour, * minute, second, millisecond and timezone. * * @param hour * an hour (0-23) of day. * @param minute * a minute (0-59) of hour. * @param second * a second (0-59) of minute. * @param millisecond * a millisecond (0-999) of second. * @return * the number of milliseconds from the epoch, or 0 upon an invalid * hour, minute, second, millisecond and timezone. */ protected static int epoch(int hour, int minute, int second, int millisecond, int timezone) { // // Validate given hour. // if (hour < 0 || 23 < hour) return 0; // // Validate given minute. // if (minute < 0 || 59 < minute) return 0; // // Validate given second. // if (second < 0 || 59 < second) return 0; // // Validate given millisecond. // if (millisecond < 0 || 999 < millisecond) return 0; // // Return number of milliseconds from the epoch. // int mMillis = hour * MILLISPERHOUR + minute * MILLISPERMINUTE + second * MILLISPERSECOND + millisecond + timezone + 1; return mMillis; } /** * Formats this object given a time pattern string. * * @param pat * a time pattern string. * @return * the time string formatted according to the given pattern string, * upon success, and the empty string, upon error. */ public String format(String pat) { if (! mValid) return ""; StringBuilder sBuf = new StringBuilder(); char prevChr = 0; int chrCnt = 0; boolean inQuoted = false; boolean inQuoteQuoted = false; // // Reset parsed time sub-elements. // // // Foreach each character of the pattern Do ... // int patLen = pat.length(); for (int i = 0; i < patLen;) { char chr = pat.charAt(i++); String sub; // // If seen a quote within a quoted string ... // if (inQuoteQuoted) { if (chr == '\'') { // cases like '...'' sBuf.append(chr); chrCnt = 0; } else { // cases like '...'M inQuoted = false; chrCnt = 1; prevChr = chr; } inQuoteQuoted = false; } // // Elif within a quoted string ... // else if (inQuoted) { if (chr == '\'') { // cases like '...' inQuoteQuoted = true; } else { // cases like '...M sBuf.append(chr); } chrCnt++; } // // Elif start of a quoted string ... // else if (chr == '\'') { if (chrCnt > 0) { // cases like ...M' sub = subFormat(prevChr, chrCnt); if (sub.length() == 0) return ""; if (! sub.equals("\u001f")) // handle empty timezone sBuf.append(sub); chrCnt = 0; prevChr = 0; } inQuoted = true; } // // Elif start of a metacharacter ... // else if (DateTimeUtil.matchChr(TIME_PICTURE_SYMBOLS, chr) || ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) { if (chr != prevChr) { if (chrCnt > 0) { // cases like HHM sub = subFormat(prevChr, chrCnt); if (sub.length() == 0) return ""; if (! sub.equals("\u001f")) // handle empty timezone sBuf.append(sub); chrCnt = 0; } prevChr = chr; } chrCnt++; } // // Elif start of a literal ... // else { if (chrCnt > 0) { // cases like MM- sub = subFormat(prevChr, chrCnt); if (sub.length() == 0) return ""; if (! sub.equals("\u001f")) // handle empty timezone sBuf.append(sub); chrCnt = 0; } if (chr == '?' || chr == '*' || chr == '+') sBuf.append(' '); else sBuf.append(chr); prevChr = 0; } } // // Ensure quoted string is terminated. // if (inQuoteQuoted) inQuoted = false; if (inQuoted) return ""; // // Format any remaining items in the pattern. // if (prevChr > 0 && chrCnt > 0) { String sub = subFormat(prevChr, chrCnt); if (sub.length() == 0) return ""; if (! sub.equals("\u001f")) // handle empty timezone sBuf.append(sub); } return sBuf.toString(); } /** * Gets this lcTime object's difference in days from Greenwich Mean. * * @return * the number of days difference from GMT, or -366 if this * object is invalid. */ public int getDays() { if (! mValid) return -366; int millis = getMillis() - 1; int bias = (millis > 0) ? 0 : -1; return (millis + bias * MILLISPERDAY) / MILLISPERDAY; } /** * Gets the hour of the day. * * @return * the hour of the day in the range 0-23, or -1 if this * object is invalid. */ public int getHour() { if (! mValid) return -1; int uhr = 0; int min = 0; int millis = getMillis() - 1; int bias = (millis > 0) ? 1 : -1; int sec = (millis + bias * MILLISPERMINUTE) % MILLISPERMINUTE / MILLISPERSECOND; if (sec < 0) min--; min += (millis + bias * MILLISPERHOUR) % MILLISPERHOUR / MILLISPERMINUTE; if (min < 0) uhr--; uhr += (millis + bias * MILLISPERDAY) % MILLISPERDAY / MILLISPERHOUR; if (uhr < 0) uhr += 24; return uhr; } /** * Gets the localized time pattern in the given style for the given locale. * * @param style * a style value: *
*
0 *
requests the locale specific default-style time pattern, *
1 *
requests the locale specific short-style time pattern, *
2 *
requests the locale specific medium-style time pattern, *
3 *
requests the locale specific long-style time pattern, and *
4 *
requests the locale specific full-style time pattern. *
* Any other value requests the default-style time pattern. * @param locale * a locale string. When empty, it will default to the default * locale. * @return * the requested time string. */ public static String getLocalTimeFormat(int style, String locale) { return new LcData(locale).getLocalTimeFormat(style); } /** * Gets the number of milliseconds since the epoch. * * @return * the number of milliseconds, or 0 if this object is * invalid. */ public int getMillis() { if (! mValid) return 0; return mMillis + mAdjustment; } /** * Gets the fraction of the second. * * @return * the fraction of the second in the range 0-999, or -1 if this * LcTime object is invalid. */ public int getMilliSecond() { if (! mValid) return -1; int millis = getMillis() - 1; int bias = (millis > 0) ? 1 : -1; int millisec = (millis + bias * MILLISPERSECOND) % MILLISPERSECOND; if (millisec < 0) millisec += 1000; return millisec; } /** * Gets the minute of the hour. * * @return * the minute of the hour in the range 0-59, or -1 if this * object is invalid. */ public int getMinute() { if (! mValid) return -1; int min = 0; int millis = getMillis() - 1; int bias = (millis > 0) ? 1 : -1; int sec = (millis + bias * MILLISPERMINUTE) % MILLISPERMINUTE / MILLISPERSECOND; if (sec < 0) min--; min += (millis + bias * MILLISPERHOUR) % MILLISPERHOUR / MILLISPERMINUTE; if (min < 0) min += 60; return min; } /** * Gets the second of the hour. * * @return * the second of the hour in the range 0-59, or -1 if this * object is invalid. */ public int getSecond() { if (! mValid) return -1; int millis = getMillis() - 1; int bias = (millis > 0) ? 1 : -1; int sec = (millis + bias * MILLISPERMINUTE) % MILLISPERMINUTE / MILLISPERSECOND; if (sec < 0) sec += 60; return sec; } /** * Gets the time pattern in the given style for the given locale. * * @param style * a style value: *
*
0 *
requests the locale specific default-style time pattern, *
1 *
requests the locale specific short-style time pattern, *
2 *
requests the locale specific medium-style time pattern, *
3 *
requests the locale specific long-style time pattern, and *
4 *
requests the locale specific full-style time pattern. *
* Any other value requests the default-style time pattern. * @param locale * a locale string. When empty, it will default to the default * locale. * @return * the requested time string. */ public static String getTimeFormat(int style, String locale) { return new LcData(locale).getTimeFormat(style); } /** * Get timezone in minutes west of Greenwich * @return timezone. */ public int getTimeZone() { if (! mValid) return -1; return mTimeZone / MILLISPERMINUTE; } private int getTimeZoneName() { // // Determine number of minutes east (+) or west (-) of Greenwich // is the current platform and whether daylight savings time applies. // TimeZone tz = TimeZone.getDefault(); int tzdiff = tz.getRawOffset() / MILLISPERMINUTE; int tzdst = tz.useDaylightTime() ? 1 : 0; String sLocName = mLocale.getIsoName(); // // Find locale-specific timezone entry in mTimeZoneName table. // int n = mTimeZoneName.length; for (int i = 0; i < n; i++) { if (mTimeZoneName[i].isoName == null) continue; if (! sLocName.equals(mTimeZoneName[i].isoName)) continue; do { if (tzdiff != mTimeZoneName[i].offset) continue; if (tzdst == mTimeZoneName[i].dstflg) return i; } while (++i < mTimeZoneName.length && mTimeZoneName[i].isoName == null); break; } return -1; } /** * Determines if this object is valid. * * @return * boolean true if valid, and false otherwise. */ public boolean isValid() { return mValid; } /** * Parses the given string according to the time pattern given. * * @param str * the time string to parse. * @param pat * the pattern string to parse. * @return * boolean true if successfully parsed, and false otherwise. */ protected boolean parse(String str, String pat) { int strPos = 0; char prevChr = 0; int chrCnt = 0; boolean inQuoted = false; boolean inQuoteQuoted = false; int strLen = str.length(); int patLen = pat.length(); int parseRes; // // Reset parsed time sub-elements. // mHourOfDay = -1; mHourOfMeriDiem = -1; mMinuteOfHour = -1; mSecondOfMinute = -1; mThousandthOfSecond = -1; mMeriDiem = -1; mTimeZone = -1; mTimeZoneSeen = false; // // Foreach each character of the pattern Do ... // for (int i = 0; i < patLen; ) { char chr = pat.charAt(i++); boolean fw = (0xFF01 <= chr && chr <= 0xFF5E); if (strPos >= strLen) { if (inQuoted && chr == '\'') { inQuoteQuoted = true; break; } return false; } // // If seen a quote within a quoted string ... // if (inQuoteQuoted) { if (chr == '\'') { // cases like '...'' if (! DateTimeUtil.matchChr(str, strPos, chr, fw)) return false; strPos += 1; chrCnt = 0; } else { // cases like '...'Y inQuoted = false; chrCnt = 1; prevChr = chr; } inQuoteQuoted = false; } // // Elif within a quoted string ... // else if (inQuoted) { if (chr == '\'') { // cases like '...' inQuoteQuoted = true; } else { // cases like '...M if (! DateTimeUtil.matchChr(str, strPos, chr, fw)) return false; strPos += 1; } chrCnt++; } // // Elif start of a quoted string ... // else if (chr == '\'') { if (chrCnt > 0) { // cases like ...M' parseRes = subParse(str, strPos, prevChr, chrCnt); if (parseRes < 0) return false; strPos = parseRes; chrCnt = 0; prevChr = 0; } inQuoted = true; } // // Elif start of a metacharacter ... // else if (DateTimeUtil.matchChr(TIME_PICTURE_SYMBOLS, chr) || ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) { if (chr != prevChr) { if (chrCnt > 0) { // cases like HHM parseRes = subParse(str, strPos, prevChr, chrCnt); if (parseRes < 0) return false; strPos = parseRes; chrCnt = 0; } prevChr = chr; } chrCnt++; } // // Elif start of a literal ... // else { if (chrCnt > 0) { // cases like MM- parseRes = subParse(str, strPos, prevChr, chrCnt); if (parseRes < 0) return false; strPos = parseRes; chrCnt = 0; prevChr = 0; } if (chr == '?') { if (strPos < strLen && Character.isDefined(str.charAt(strPos))) strPos += 1; } else if (chr == '+') { if (strPos >= strLen || ! Character.isWhitespace(str.charAt(strPos))) return false; strPos += 1; while (strPos < strLen && Character.isWhitespace(str.charAt(strPos))) strPos += 1; } else if (chr == '*') { while (strPos < strLen && Character.isWhitespace(str.charAt(strPos))) strPos += 1; } else if (strPos < strLen && str.charAt(strPos) == chr) { strPos += 1; } else { return false; } } } // // Ensure quoted string is terminated. // if (inQuoteQuoted) inQuoted = false; if (inQuoted) return false; // // Parse any remaining items in the pattern. // if (prevChr > 0 && chrCnt > 0) { parseRes = subParse(str, strPos, prevChr, chrCnt); if (parseRes < 0) return false; strPos = parseRes; } // // Ensure there's no more source to parse. // if (strPos != strLen) return false; // // Adjust hour of day if meridiem were parsed. // if (mHourOfMeriDiem >= 0 && mMeriDiem >= 0) mHourOfDay = mHourOfMeriDiem + mMeriDiem * 12; // // Adjust milliseconds if none were parsed. // if (mThousandthOfSecond == -1) mThousandthOfSecond = 0; // // Adjust seconds if none were parsed. // if (mSecondOfMinute == -1) mSecondOfMinute = 0; // // Ensure sufficient data was supplied for a mValid time. // if (mHourOfDay < 0 || mMinuteOfHour < 0) return false; // // Adjust for local time if no timezone was parsed. // if (! mTimeZoneSeen) { Calendar now = Calendar.getInstance(); mTimeZone = - now.get(Calendar.ZONE_OFFSET); if (TimeZone.getDefault().inDaylightTime(now.getTime())) mTimeZone -= now.get(Calendar.DST_OFFSET); } return true; } /** * Sets this object to operate on Greenwich Mean time, which is the * default. Any subsequent calls to the format method will result in time * strings that are expressed in Greenwich Mean time. */ public void setGMTime() { mAdjustment = 0; mDaylightSavingsTime = false; } /** * Sets this object to operate on local time as opposed to the * default, which is Greenwich Mean time. Any subsequent calls to the format * method will result in time strings that are expressed in local time. */ public void setLocalTime() { Calendar now = Calendar.getInstance(); mAdjustment = now.get(Calendar.ZONE_OFFSET); mDaylightSavingsTime = TimeZone.getDefault().inDaylightTime(now.getTime()); if (mDaylightSavingsTime) mAdjustment += now.get(Calendar.DST_OFFSET); } /** * Sets this object locale-specific time symbols for the locale given. * * @param locale * a valid locale name. */ protected void setTimeSymbols(String locale) { LcData oData = new LcData(locale); for (int i = 0; i < 2; i++) mSymbols.meridiemName[i] = oData.getMeridiemName(i); mSymbols.zeroDigit = oData.getZeroSymbol().charAt(0); } /** * Formats a sub-element of this object given the number of occurances * of a time pattern metacharacter. * * @param chr * a time pattern metacharacter. * @param chrCnt * the number of consecutive occurances of the metacharacter. * @return * the formatted sub-element, or the empty string upon error. */ protected String subFormat(char chr, int chrCnt) { StringBuilder sBuf = new StringBuilder(); boolean fw = (0xFF01 <= chr && chr <= 0xFF5E); int tr = 0; // // Identify locale's table of ideographic numeric characters. // char[] pCJK_Num = null; if (mLocale.isJapanese()) pCJK_Num = DateTimeUtil.Kanji_Num; else if (mLocale.isTraditionalChinese()) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.getName().equals(LcLocale.Chinese_HongKong)) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.isChinese()) pCJK_Num = DateTimeUtil.Kanji_Num; else if (mLocale.isKoreanHani()) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.isKorean()) pCJK_Num = DateTimeUtil.Hangul_Num; // // Handle each supported LcTime sub-element. // int value = 0; switch (chr) { case 0xFF48: // Fullwidth 'h' Hour: 12-11 based. if ((value = getHour() % 12) == 0) value = 12; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? - 1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'h': // Hour: 12-11 based. if (chr == 'h') if ((value = getHour() % 12) == 0) value = 12; switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 0xFF4B: // Fullwidth 'k' Hour: 0-11 based. value = getHour() % 12; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? -1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'k': // Hour: 0-11 based. if (chr == 'k') value = getHour() % 12; switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 0xFF28: // Fullwidth 'H' Hour Of Day 0-23 based. value = getHour(); switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? -1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'H': // Hour Of Day 0-23 based. if (chr == 'H') value = getHour(); switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 0xFF2B: // Fullwidth 'K' Hour Of Day: 24-23 based. if ((value = getHour()) == 0) value = 24; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? -1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'K': // Hour Of Day: 24-23 based. if (chr == 'K') if ((value = getHour()) == 0) value = 24; switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 0xFF2D: // Fullwidth 'M' Minute Of Hour value = getMinute(); switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? -1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'M': // Minute Of Hour if (chr == 'M') value = getMinute(); switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 0xFF33: // Fullwidth 'S' Second Of Instant value = getSecond(); switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4) ? -1 : 0; else if (mLocale.isKorean()) tr = -1; else if (mLocale.isChinese()) tr = 1; sBuf.append(DateTimeUtil.fmtNum(2, value, pCJK_Num, tr)); break; } /* FALLTHRU */ case 'S': // Second Of Instant if (chr == 'S') value = getSecond(); switch (chrCnt) { case 1: sBuf.append(DateTimeUtil.fmtPlainNum(2, value, fw, mSymbols.zeroDigit)); break; case 2: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 'F': case 0xFF26: // Milliseconds value = getMilliSecond(); switch (chrCnt) { case 3: sBuf.append(DateTimeUtil.fmtNum(chrCnt, value, fw, mSymbols.zeroDigit)); break; } break; case 'A': // Meridiem value = (getHour() >= 12) ? 1 : 0; switch (chrCnt) { case 1: case 2: // Acrobat t format. if (chrCnt == 1) { sBuf.append(DateTimeUtil.fmtStr( mSymbols.meridiemName[value], fw)); } else { String meridiemName[] = new String[2]; for (int i = 0; i < 2; i++) { int k = 1; meridiemName[i] = mSymbols.meridiemName[i].substring(0, k); } sBuf.append(DateTimeUtil.fmtStr(meridiemName[value], fw)); } break; } break; case 'Z': // Abbreviated Time Zone int idx = getTimeZoneName(); switch (chrCnt) { case 1: // // For time zones that have names, use them. // if (mAdjustment != 0 && idx >= 0 && mTimeZoneName[idx].stdName != null) { if (mDaylightSavingsTime || mTimeZoneName[idx].dstflg == 0) sBuf.append(DateTimeUtil.fmtStr( mTimeZoneName[idx].dstName, fw)); else sBuf.append(DateTimeUtil.fmtStr( mTimeZoneName[idx].stdName, fw)); } // // For time zones that have no names, use // GMT+hours:minutes and GMT-hours:minutes. // else { value = mAdjustment; sBuf.append(DateTimeUtil.fmtStr("GMT", fw)); if (value < 0) { sBuf.append(DateTimeUtil.matchChr('-', fw)); value = -value; } else if (value > 0) { sBuf.append(DateTimeUtil.matchChr('+', fw)); } if (value != 0) { sBuf.append(DateTimeUtil.fmtNum(2, value / MILLISPERHOUR, fw, mSymbols.zeroDigit)); sBuf.append(DateTimeUtil.matchChr(':', fw)); value = (value % MILLISPERHOUR) / MILLISPERMINUTE; sBuf.append(DateTimeUtil.fmtNum(2, value, fw, mSymbols.zeroDigit)); } } break; case 2: // Acrobat Z format case 3: // Acrobat ZZ format value = mAdjustment; if (value == 0) { sBuf.append(((chrCnt == 3) ? DateTimeUtil.matchChr('Z', fw) : '\u001f')); } else if (value < 0) { sBuf.append(DateTimeUtil.matchChr('-', fw)); value = -value; } else if (value > 0) { sBuf.append(DateTimeUtil.matchChr('+', fw)); } if (value != 0) { sBuf.append(DateTimeUtil.fmtNum(2, value / MILLISPERHOUR, fw, mSymbols.zeroDigit)); sBuf.append(DateTimeUtil.matchChr('\'', fw)); value = (value % MILLISPERHOUR) / MILLISPERMINUTE; sBuf.append(DateTimeUtil.fmtNum(2, value, fw, mSymbols.zeroDigit)); sBuf.append(DateTimeUtil.matchChr('\'', fw)); } break; } break; case 'z': case 0xFF5A: // XFA Time Zone switch (chrCnt) { case 1: case 2: value = mAdjustment; if (value == 0) { sBuf.append(DateTimeUtil.matchChr('Z', fw)); } else if (value < 0) { sBuf.append(DateTimeUtil.matchChr('-', fw)); value = -value; } else if (value > 0) { sBuf.append(DateTimeUtil.matchChr('+', fw)); } if (value != 0) { sBuf.append(DateTimeUtil.fmtNum(2, value / MILLISPERHOUR, fw, mSymbols.zeroDigit)); if (chrCnt == 2) sBuf.append(DateTimeUtil.matchChr(':', fw)); value = (value % MILLISPERHOUR) / MILLISPERMINUTE; sBuf.append(DateTimeUtil.fmtNum(2, value, fw, mSymbols.zeroDigit)); } break; } break; case 't': // tab. while (chrCnt-- > 0) { sBuf.append('\t'); } break; default: sBuf.append(chr); break; } return sBuf.toString(); } /** * Parses a sub-element at a given position of the given string, * given the number of occurances of a time pattern metacharacter. * * @param src * the time string to parse. * @param srcPos * the starting parsing position within the time string. * @param chr * a time pattern metacharacter. * @param chrCnt * the number of consecutive occurances of the metacharacter. * * @return * the ending parsing position within the time string * if successfully parsed, and -1 otherwise. */ protected int subParse(String src, int srcPos, char chr, int chrCnt) { int len; int idx; int curPos = srcPos; int srcLen = src.length(); boolean fw = (0xFF01 <= chr && chr <= 0xFF5E); boolean tr = false; // // Identify locale's table of ideographic numeric characters. // char[] pCJK_Num = null; if (mLocale.isJapanese()) pCJK_Num = DateTimeUtil.Kanji_Num; else if (mLocale.isTraditionalChinese()) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.getName().equals(LcLocale.Chinese_HongKong)) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.isChinese()) pCJK_Num = DateTimeUtil.Kanji_Num; else if (mLocale.isKoreanHani()) pCJK_Num = DateTimeUtil.Hanja_Num; else if (mLocale.isKorean()) pCJK_Num = DateTimeUtil.Hangul_Num; // // Handle each supported LcTime sub-element. // switch (chr) { case 0xFF48: // Fullwidth 'h' Hour: 12-11 based. if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfMeriDiem = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'h': // Hour: 12-11 based. if (chr == 'h') if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfMeriDiem = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'h') return -1; break; } if (mHourOfMeriDiem < 1 || 12 < mHourOfMeriDiem) return -1; if (mHourOfMeriDiem == 12) mHourOfMeriDiem = 0; break; case 0xFF4B: // Fullwidth 'k' Hour: 0-11 based. if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfMeriDiem = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'k': // Hour: 0-11 based. if (chr == 'k') if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfMeriDiem = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'k') return -1; break; } if (mHourOfMeriDiem < 0 || 11 < mHourOfMeriDiem) return -1; break; case 0xFF28: // Fullwidth 'H' Hour Of Day 0-23 based. if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfDay = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'H': // Hour Of Day 0-23 based. if (chr == 'H') if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfDay = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'H') return -1; break; } if (mHourOfDay < 0 || 23 < mHourOfDay) return -1; break; case 0xFF2B: // Fullwidth 'K' Hour Of Day: 24-23 based. if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfDay = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'K': // Hour Of Day: 24-23 based. if (chr == 'K') if (mHourOfDay >= 0 || mHourOfMeriDiem >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mHourOfDay = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'K') return -1; break; } if (mHourOfDay < 1 || 24 < mHourOfDay) return -1; if (mHourOfDay == 24) mHourOfDay = 0; break; case 0xFF2D: // Fullwidth 'M' Minute Of Hour if (mMinuteOfHour >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mMinuteOfHour = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'M': // Minute Of Hour if (chr == 'M') if (mMinuteOfHour >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mMinuteOfHour = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'M') return -1; break; } if (mMinuteOfHour < 0 || 59 < mMinuteOfHour) return -1; break; case 0xFF33: // Fullwidth 'S' Second Of Instant if (mSecondOfMinute >= 0) return -1; switch (chrCnt) { case 3: case 4: if (mLocale.isJapanese()) tr = (chrCnt == 4); else if (mLocale.isKorean()) tr = true; else if (mLocale.isChinese()) tr = true; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, pCJK_Num, tr); if (len <= 0) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mSecondOfMinute = DateTimeUtil.getNum(src, srcPos, curPos, pCJK_Num, tr); srcPos = curPos; break; } /*FALLTHRU*/ case 'S': // Second Of Instant if (chr == 'S') if (mSecondOfMinute >= 0) return -1; switch (chrCnt) { case 1: case 2: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len < chrCnt) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mSecondOfMinute = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: if (chr == 'S') return -1; break; } if (mSecondOfMinute < 0 || 59 < mSecondOfMinute) return -1; break; case 'F': case 0xFF26: // Milliseconds if (mThousandthOfSecond >= 0) return -1; switch (chrCnt) { case 3: len = DateTimeUtil.matchNum(src, srcPos, srcPos + 3, fw, mSymbols.zeroDigit); if (len != 3) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); mThousandthOfSecond = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); srcPos = curPos; break; default: return -1; } if (mThousandthOfSecond < 0 || 999 < mSecondOfMinute) return -1; break; case 'A': // Meridiem if (mMeriDiem >= 0) return -1; switch (chrCnt) { case 1: case 2: if (chrCnt == 1) { idx = DateTimeUtil.matchName(src, srcPos, mSymbols.meridiemName, true); if (idx < 0) return -1; len = mSymbols.meridiemName[idx].length(); } else /* if (chrCnt == 2) */ { // Acrobat t format. String[] meridiemName = new String[2]; for (int i = 0; i < 2; i++) { meridiemName[i] = mSymbols.meridiemName[i].substring(0, 1); } idx = DateTimeUtil.matchName(src, srcPos, meridiemName, true); if (idx < 0) return -1; len = meridiemName[idx].length(); } mMeriDiem = idx; srcPos += len; break; default: return -1; } break; case 'Z': // Abbreviated Time Zone if (mTimeZoneSeen) return -1; mTimeZoneSeen = true; switch (chrCnt) { case 1: // // For unamed time zones, try parsing // GMT[+HH:MM] or GMT[-HH:MM]. // len = DateTimeUtil.matchStr(src, srcPos, "GMT", fw); if (len > 0) { srcPos = len; if (srcPos == srcLen) { mTimeZone = 0; return srcPos; } else if (DateTimeUtil.matchChr(src, srcPos, '-', fw)) { srcPos += 1; mTimeZone = 1; } else if (DateTimeUtil.matchChr(src, srcPos, '+', fw)) { srcPos += 1; mTimeZone = -1; } else { mTimeZone = 0; return srcPos; } len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); int hours = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (hours < 0 || 12 < hours) return -1; srcPos = curPos; if (! DateTimeUtil.matchChr(src, srcPos, ':', fw)) return -1; srcPos += 1; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); int minutes = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (minutes < 0 || 59 < minutes) return -1; srcPos = curPos; mTimeZone *= ((hours * 60) + minutes) * MILLISPERMINUTE; } // // For named time zones, try matching locale's timezone names. // else { String sLocName = mLocale.getIsoName(); // // Locate our locale within timezone table. // int k, n = mTimeZoneName.length; for (k = 0; k < n; k++) { if (mTimeZoneName[k].isoName != null && sLocName.equals(mTimeZoneName[k].isoName)) break; } // // Check if matched abbreviated standard zones. // for (int i = k; i < n; i++) { if (mTimeZoneName[i].stdName == null) break; String tz = mTimeZoneName[i].stdName; int tzLen = tz.length(); if (srcPos + tzLen > srcLen) continue; len = DateTimeUtil.matchStr(src, srcPos, tz, fw); if (len > 0) { mTimeZone = - mTimeZoneName[i].offset * MILLISPERMINUTE; srcPos = len; return srcPos; } // // Limit search to this locale's timezone data. // if (i + 1 < n && mTimeZoneName[i + 1].isoName != null) break; } // // Check if matched abbreviated daylight zones. // for (int i = k; i < n; i++) { if (mTimeZoneName[i].dstName == null) break; String tz = mTimeZoneName[i].dstName; int tzLen = tz.length(); if (srcPos + tzLen > srcLen) continue; len = DateTimeUtil.matchStr(src, srcPos, tz, fw); if (len > 0) { mTimeZone = - mTimeZoneName[i].offset * MILLISPERMINUTE; mTimeZone -= MILLISPERHOUR; srcPos = len; return srcPos; } // // Limit search to this locale's timezone data. // if (i + 1 < n && mTimeZoneName[i + 1].isoName != null) break; } return -1; } break; case 2: // strings: [+-]HH'MM'. case 3: // strings: Z | [+-]HH'MM'. len = DateTimeUtil.matchStr(src, srcPos, "Z", fw); if (len > 0) { mTimeZone = 0; return srcPos; } else { int direction = 0; if (DateTimeUtil.matchChr(src, srcPos, '-', fw)) { srcPos += 1; direction = 1; } else if (DateTimeUtil.matchChr(src, srcPos, '+', fw)) { srcPos += 1; direction = -1; } if (direction == 0) { if (chrCnt == 2) return -1; mTimeZone = 0; return srcPos; } len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); int hours = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (hours < 0 || 12 < hours) return -1; srcPos = curPos; mTimeZone = direction * (hours * 60) * MILLISPERMINUTE; if (! DateTimeUtil.matchChr(src, srcPos, '\'', fw)) return -1; srcPos += 1; len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return srcPos; curPos = DateTimeUtil.incPos(src, srcPos, len); int minutes = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (minutes < 0 || 59 < minutes) return -1; srcPos = curPos; if (! DateTimeUtil.matchChr(src, srcPos, '\'', fw)) return -1; srcPos += 1; mTimeZone += direction * minutes * MILLISPERMINUTE; } break; default: return -1; } break; case 'z': case 0xFF5A: // XFA Time Zone if (mTimeZoneSeen) return -1; mTimeZoneSeen = true; switch (chrCnt) { case 1: // strings: Z or [+-]HH[MM]. case 2: // strings: Z or [+-]HH[:MM]. if (DateTimeUtil.matchChr(src, srcPos, 'Z', fw)) { srcPos += 1; mTimeZone = 0; } else if (DateTimeUtil.matchChr(src, srcPos, 'z', fw)) { srcPos += 1; mTimeZone = 0; } else { int direction = 0; if (DateTimeUtil.matchChr(src, srcPos, '-', fw)) { srcPos += 1; direction = 1; } else if (DateTimeUtil.matchChr(src, srcPos, '+', fw)) { srcPos += 1; direction = -1; } len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return -1; curPos = DateTimeUtil.incPos(src, srcPos, len); int hours = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (hours < 0 || 12 < hours) return -1; mTimeZone = direction * (hours * 60) * MILLISPERMINUTE; srcPos = curPos; if (srcPos == srcLen) return srcPos; if (chrCnt == 2) { if (! DateTimeUtil.matchChr(src, srcPos, ':', fw)) return srcPos; srcPos += 1; } len = DateTimeUtil.matchNum(src, srcPos, srcPos + 2, fw, mSymbols.zeroDigit); if (len != 2) return srcPos; curPos = DateTimeUtil.incPos(src, srcPos, len); int minutes = DateTimeUtil.getNum(src, srcPos, curPos, fw, mSymbols.zeroDigit); if (minutes < 0 || 59 < minutes) return -1; mTimeZone += direction * minutes * MILLISPERMINUTE; srcPos = curPos; } break; default: return -1; } break; case 't': // tab while (chrCnt-- != 0) { if (src.charAt(srcPos) != '\t') return -1; srcPos += 1; } break; default: if (! DateTimeUtil.matchChr(src, srcPos, chr, fw)) return -1; srcPos += 1; break; } return srcPos; } /** * Formats this object according to the default pattern. * * @return * the time string formatted according to the default pattern, upon * success, and the empty string, upon error. */ public String toString() { return format(DEFAULT_TIME_FMT); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy