12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
3bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/*
4bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *******************************************************************************
5bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Copyright (C) 2004-2008, International Business Machines Corporation and    *
6bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * others. All Rights Reserved.                                                *
7bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *******************************************************************************
8bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *
9bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */
10bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
11bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpackage com.ibm.icu.dev.tool.timescale;
12bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
13bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Date;
14bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Locale;
15bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
16bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.text.MessageFormat;
17bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.Calendar;
18bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.GregorianCalendar;
19bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.SimpleTimeZone;
20bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.TimeZone;
21bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
22bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/**
23bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * This tool calculates the numeric values of the epoch offsets
24bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * used in UniversalTimeScale.
25bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *
26bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @see com.ibm.icu.util.UniversalTimeScale
27bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */
28bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpublic class EpochOffsets
29bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert{
30bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
31bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
32bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * The default constructor.
33bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     */
34bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public EpochOffsets()
35bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    {
36bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
37bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
38bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long ticks        = 1;
39bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long microseconds = ticks * 10;
40bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long milliseconds = microseconds * 1000;
41bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long seconds      = milliseconds * 1000;
42bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long minutes      = seconds * 60;
43bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long hours        = minutes * 60;
44bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long days         = hours * 24;
45bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    // Java measures time in milliseconds, not in 100ns ticks.
46bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long javaDays     = days / milliseconds;
47bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
48bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static int[][] epochDates = {
49bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {   1, Calendar.JANUARY,   1},
50bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {1970, Calendar.JANUARY,   1},
51bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {1601, Calendar.JANUARY,   1},
52bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {1904, Calendar.JANUARY,   1},
53bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {2001, Calendar.JANUARY,   1},
54bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {1899, Calendar.DECEMBER, 31},
55bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {1900, Calendar.MARCH,     1}
56bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    };
57bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
58bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
59bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * The <code>main()</code> method calculates the epoch offsets used by the
60bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * <code>UniversalTimeScale</code> class.
61bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     *
62bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * The calculations are done using an ICU <code>Calendar</code> object. The first step is
63bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * to calculate the Universal Time Scale's epoch date. Then the epoch offsets are calculated
64bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * by calculating each epoch date, subtracting the universal epoch date from it, and converting
65bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * that value to ticks.
66bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     *
67bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * @param args - the command line arguments.
68bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     */
69bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public static void main(String[] args)
70bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    {
71bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        TimeZone utc = new SimpleTimeZone(0, "UTC");
72bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
73bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // Jitterbug 5211: .Net System.DateTime uses the proleptic calendar,
74bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // while ICU by default uses the Julian calendar before 1582.
75bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // Original code: Calendar cal = Calendar.getInstance(utc, Locale.ENGLISH);
76bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // Use a proleptic Gregorian calendar for 0001AD and later by setting
77bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // the Gregorian change date before 0001AD with a value
78bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // that is safely before that date by any measure, i.e.,
79bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // more than 719164 days before 1970.
80bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        long before0001AD = -1000000 * javaDays;
81bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        GregorianCalendar cal = new GregorianCalendar(utc, Locale.ENGLISH);
82bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        cal.setGregorianChange(new Date(before0001AD));
83bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
84bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        MessageFormat fmt = new MessageFormat("{0, date, full} {0, time, full} = {1}");
85bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        Object arguments[] = {cal, null};
86bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
87bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        System.out.println("Epoch offsets:");
88bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
89bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // January 1, 0001 00:00:00 is the universal epoch date...
90bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        cal.set(1, Calendar.JANUARY, 1, 0, 0, 0);
91bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
92bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        long universalEpoch = cal.getTimeInMillis();
93bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
94bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        for (int i = 0; i < epochDates.length; i += 1) {
95bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int[] date = epochDates[i];
96bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
97bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            cal.set(date[0], date[1], date[2]);
98bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
99bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            long millis = cal.getTimeInMillis();
100bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
101bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            arguments[1] = Long.toString((millis - universalEpoch) * milliseconds);
102bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
103bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            System.out.println(fmt.format(arguments));
104bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert         }
105bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
106bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert}
107