org.orekit.time.AbsoluteDateTest.java Source code

Java tutorial

Introduction

Here is the source code for org.orekit.time.AbsoluteDateTest.java

Source

/* Copyright 2002-2015 CS Systmes d'Information
 * Licensed to CS Systmes d'Information (CS) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * CS licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.orekit.time;

import java.util.Date;

import org.apache.commons.math3.util.FastMath;
import org.apache.commons.math3.util.Precision;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.Utils;
import org.orekit.errors.OrekitException;
import org.orekit.utils.Constants;

public class AbsoluteDateTest {

    @Test
    public void testStandardEpoch() throws OrekitException {
        TimeScale tai = TimeScalesFactory.getTAI();
        TimeScale tt = TimeScalesFactory.getTT();
        Assert.assertEquals(-210866760000000l, AbsoluteDate.JULIAN_EPOCH.toDate(tt).getTime());
        Assert.assertEquals(-3506716800000l, AbsoluteDate.MODIFIED_JULIAN_EPOCH.toDate(tt).getTime());
        Assert.assertEquals(-631152000000l, AbsoluteDate.FIFTIES_EPOCH.toDate(tt).getTime());
        Assert.assertEquals(-378691200000l, AbsoluteDate.CCSDS_EPOCH.toDate(tai).getTime());
        Assert.assertEquals(935280032000l, AbsoluteDate.GALILEO_EPOCH.toDate(tai).getTime());
        Assert.assertEquals(315964819000l, AbsoluteDate.GPS_EPOCH.toDate(tai).getTime());
        Assert.assertEquals(946728000000l, AbsoluteDate.J2000_EPOCH.toDate(tt).getTime());
    }

    @Test
    public void testStandardEpochStrings() throws OrekitException {
        Assert.assertEquals("-4712-01-01T12:00:00.000",
                AbsoluteDate.JULIAN_EPOCH.toString(TimeScalesFactory.getTT()));
        Assert.assertEquals("1858-11-17T00:00:00.000",
                AbsoluteDate.MODIFIED_JULIAN_EPOCH.toString(TimeScalesFactory.getTT()));
        Assert.assertEquals("1950-01-01T00:00:00.000",
                AbsoluteDate.FIFTIES_EPOCH.toString(TimeScalesFactory.getTT()));
        Assert.assertEquals("1958-01-01T00:00:00.000",
                AbsoluteDate.CCSDS_EPOCH.toString(TimeScalesFactory.getTAI()));
        Assert.assertEquals("1999-08-22T00:00:00.000",
                AbsoluteDate.GALILEO_EPOCH.toString(TimeScalesFactory.getUTC()));
        Assert.assertEquals("1980-01-06T00:00:00.000", AbsoluteDate.GPS_EPOCH.toString(TimeScalesFactory.getUTC()));
        Assert.assertEquals("2000-01-01T12:00:00.000",
                AbsoluteDate.J2000_EPOCH.toString(TimeScalesFactory.getTT()));
        Assert.assertEquals("1970-01-01T00:00:00.000",
                AbsoluteDate.JAVA_EPOCH.toString(TimeScalesFactory.getUTC()));
    }

    @Test
    public void testJulianEpochRate() throws OrekitException {

        for (int i = 0; i < 10; ++i) {
            AbsoluteDate j200i = AbsoluteDate.createJulianEpoch(2000.0 + i);
            AbsoluteDate j2000 = AbsoluteDate.J2000_EPOCH;
            double expected = i * Constants.JULIAN_YEAR;
            Assert.assertEquals(expected, j200i.durationFrom(j2000), 4.0e-15 * expected);
        }

    }

    @Test
    public void testBesselianEpochRate() throws OrekitException {

        for (int i = 0; i < 10; ++i) {
            AbsoluteDate b195i = AbsoluteDate.createBesselianEpoch(1950.0 + i);
            AbsoluteDate b1950 = AbsoluteDate.createBesselianEpoch(1950.0);
            double expected = i * Constants.BESSELIAN_YEAR;
            Assert.assertEquals(expected, b195i.durationFrom(b1950), 4.0e-15 * expected);
        }

    }

    @Test
    public void testLieske() throws OrekitException {

        // the following test values correspond to table 1 in the paper:
        // Precession Matrix Based on IAU (1976) System of Astronomical Constants,
        // Jay H. Lieske, Astronomy and Astrophysics, vol. 73, no. 3, Mar. 1979, p. 282-284
        // http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1979A%26A....73..282L&defaultprint=YES&filetype=.pdf

        // published table, with limited accuracy
        final double publishedEpsilon = 1.0e-6 * Constants.JULIAN_YEAR;
        checkEpochs(1899.999142, 1900.000000, publishedEpsilon);
        checkEpochs(1900.000000, 1900.000858, publishedEpsilon);
        checkEpochs(1950.000000, 1949.999790, publishedEpsilon);
        checkEpochs(1950.000210, 1950.000000, publishedEpsilon);
        checkEpochs(2000.000000, 1999.998722, publishedEpsilon);
        checkEpochs(2000.001278, 2000.000000, publishedEpsilon);

        // recomputed table, using directly Lieske formulas (i.e. *not* Orekit implementation) with high accuracy
        final double accurateEpsilon = 1.2e-13 * Constants.JULIAN_YEAR;
        checkEpochs(1899.99914161068724704, 1900.00000000000000000, accurateEpsilon);
        checkEpochs(1900.00000000000000000, 1900.00085837097878165, accurateEpsilon);
        checkEpochs(1950.00000000000000000, 1949.99979044229979466, accurateEpsilon);
        checkEpochs(1950.00020956217615449, 1950.00000000000000000, accurateEpsilon);
        checkEpochs(2000.00000000000000000, 1999.99872251362080766, accurateEpsilon);
        checkEpochs(2000.00127751366506194, 2000.00000000000000000, accurateEpsilon);

    }

    private void checkEpochs(final double besselianEpoch, final double julianEpoch, final double epsilon) {
        final AbsoluteDate b = AbsoluteDate.createBesselianEpoch(besselianEpoch);
        final AbsoluteDate j = AbsoluteDate.createJulianEpoch(julianEpoch);
        Assert.assertEquals(0.0, b.durationFrom(j), epsilon);
    }

    @Test
    public void testParse() throws OrekitException {
        Assert.assertEquals(AbsoluteDate.MODIFIED_JULIAN_EPOCH,
                new AbsoluteDate("1858-W46-3", TimeScalesFactory.getTT()));
        Assert.assertEquals(AbsoluteDate.JULIAN_EPOCH,
                new AbsoluteDate("-4712-01-01T12:00:00.000", TimeScalesFactory.getTT()));
        Assert.assertEquals(AbsoluteDate.FIFTIES_EPOCH, new AbsoluteDate("1950-01-01", TimeScalesFactory.getTT()));
        Assert.assertEquals(AbsoluteDate.CCSDS_EPOCH, new AbsoluteDate("1958-001", TimeScalesFactory.getTAI()));
    }

    @Test
    public void testParseLeap() throws OrekitException {
        TimeScale utc = TimeScalesFactory.getUTC();
        AbsoluteDate beforeLeap = new AbsoluteDate("2012-06-30T23:59:59.8", utc);
        AbsoluteDate inLeap = new AbsoluteDate("2012-06-30T23:59:60.5", utc);
        Assert.assertEquals(0.7, inLeap.durationFrom(beforeLeap), 1.0e-12);
        Assert.assertEquals("2012-06-30T23:59:60.500", inLeap.toString(utc));
    }

    @Test
    public void testOutput() {
        TimeScale tt = TimeScalesFactory.getTT();
        Assert.assertEquals("1950-01-01T01:01:01.000", AbsoluteDate.FIFTIES_EPOCH.shiftedBy(3661.0).toString(tt));
        Assert.assertEquals("2000-01-01T13:01:01.000", AbsoluteDate.J2000_EPOCH.shiftedBy(3661.0).toString(tt));
    }

    @Test
    public void testJ2000() {
        Assert.assertEquals("2000-01-01T12:00:00.000",
                AbsoluteDate.J2000_EPOCH.toString(TimeScalesFactory.getTT()));
        Assert.assertEquals("2000-01-01T11:59:27.816",
                AbsoluteDate.J2000_EPOCH.toString(TimeScalesFactory.getTAI()));
        Assert.assertEquals("2000-01-01T11:58:55.816", AbsoluteDate.J2000_EPOCH.toString(utc));
    }

    @Test
    public void testFraction() {
        AbsoluteDate d = new AbsoluteDate(new DateComponents(2000, 01, 01), new TimeComponents(11, 59, 27.816),
                TimeScalesFactory.getTAI());
        Assert.assertEquals(0, d.durationFrom(AbsoluteDate.J2000_EPOCH), 1.0e-10);
    }

    @Test
    public void testScalesOffset() {
        AbsoluteDate date = new AbsoluteDate(new DateComponents(2006, 02, 24), new TimeComponents(15, 38, 00), utc);
        Assert.assertEquals(33, date.timeScalesOffset(TimeScalesFactory.getTAI(), utc), 1.0e-10);
    }

    @Test
    public void testUTC() {
        AbsoluteDate date = new AbsoluteDate(new DateComponents(2002, 01, 01), new TimeComponents(00, 00, 01), utc);
        Assert.assertEquals("2002-01-01T00:00:01.000", date.toString());
    }

    @Test
    public void test1970() {
        AbsoluteDate date = new AbsoluteDate(new Date(0l), utc);
        Assert.assertEquals("1970-01-01T00:00:00.000", date.toString());
    }

    @Test
    public void testUtcGpsOffset() {
        AbsoluteDate date1 = new AbsoluteDate(new DateComponents(2005, 8, 9), new TimeComponents(16, 31, 17), utc);
        AbsoluteDate date2 = new AbsoluteDate(new DateComponents(2006, 8, 9), new TimeComponents(16, 31, 17), utc);
        AbsoluteDate dateRef = new AbsoluteDate(new DateComponents(1980, 1, 6), TimeComponents.H00, utc);

        // 13 seconds offset between GPS time and UTC in 2005
        long noLeapGap = ((9347 * 24 + 16) * 60 + 31) * 60 + 17;
        long realGap = (long) date1.durationFrom(dateRef);
        Assert.assertEquals(13l, realGap - noLeapGap);

        // 14 seconds offset between GPS time and UTC in 2006
        noLeapGap = ((9712 * 24 + 16) * 60 + 31) * 60 + 17;
        realGap = (long) date2.durationFrom(dateRef);
        Assert.assertEquals(14l, realGap - noLeapGap);

    }

    @Test
    public void testGpsDate() {
        AbsoluteDate date = AbsoluteDate.createGPSDate(1387, 318677000.0);
        AbsoluteDate ref = new AbsoluteDate(new DateComponents(2006, 8, 9), new TimeComponents(16, 31, 03), utc);
        Assert.assertEquals(0, date.durationFrom(ref), 1.0e-15);
    }

    @Test
    public void testMJDDate() throws OrekitException {
        AbsoluteDate dateA = AbsoluteDate.createMJDDate(51544, 0.5 * Constants.JULIAN_DAY,
                TimeScalesFactory.getTT());
        Assert.assertEquals(0.0, AbsoluteDate.J2000_EPOCH.durationFrom(dateA), 1.0e-15);
        AbsoluteDate dateB = AbsoluteDate.createMJDDate(53774, 0.0, TimeScalesFactory.getUTC());
        AbsoluteDate dateC = new AbsoluteDate("2006-02-08T00:00:00", TimeScalesFactory.getUTC());
        Assert.assertEquals(0.0, dateC.durationFrom(dateB), 1.0e-15);
    }

    @Test
    public void testJDDate() {
        final AbsoluteDate date = AbsoluteDate.createJDDate(2400000, 0.5 * Constants.JULIAN_DAY,
                TimeScalesFactory.getTT());
        Assert.assertEquals(0.0, AbsoluteDate.MODIFIED_JULIAN_EPOCH.durationFrom(date), 1.0e-15);
    }

    @Test
    public void testOffsets() {
        final TimeScale tai = TimeScalesFactory.getTAI();
        AbsoluteDate leapStartUTC = new AbsoluteDate(1976, 12, 31, 23, 59, 59, utc);
        AbsoluteDate leapEndUTC = new AbsoluteDate(1977, 1, 1, 0, 0, 0, utc);
        AbsoluteDate leapStartTAI = new AbsoluteDate(1977, 1, 1, 0, 0, 14, tai);
        AbsoluteDate leapEndTAI = new AbsoluteDate(1977, 1, 1, 0, 0, 16, tai);
        Assert.assertEquals(leapStartUTC, leapStartTAI);
        Assert.assertEquals(leapEndUTC, leapEndTAI);
        Assert.assertEquals(1, leapEndUTC.offsetFrom(leapStartUTC, utc), 1.0e-10);
        Assert.assertEquals(1, leapEndTAI.offsetFrom(leapStartTAI, utc), 1.0e-10);
        Assert.assertEquals(2, leapEndUTC.offsetFrom(leapStartUTC, tai), 1.0e-10);
        Assert.assertEquals(2, leapEndTAI.offsetFrom(leapStartTAI, tai), 1.0e-10);
        Assert.assertEquals(2, leapEndUTC.durationFrom(leapStartUTC), 1.0e-10);
        Assert.assertEquals(2, leapEndTAI.durationFrom(leapStartTAI), 1.0e-10);
    }

    @Test
    public void testBeforeAndAfterLeap() {
        final TimeScale tai = TimeScalesFactory.getTAI();
        AbsoluteDate leapStart = new AbsoluteDate(1977, 1, 1, 0, 0, 14, tai);
        AbsoluteDate leapEnd = new AbsoluteDate(1977, 1, 1, 0, 0, 16, tai);
        for (int i = -10; i < 10; ++i) {
            final double dt = 1.1 * (2 * i - 1);
            AbsoluteDate d1 = leapStart.shiftedBy(dt);
            AbsoluteDate d2 = new AbsoluteDate(leapStart, dt, tai);
            AbsoluteDate d3 = new AbsoluteDate(leapStart, dt, utc);
            AbsoluteDate d4 = new AbsoluteDate(leapEnd, dt, tai);
            AbsoluteDate d5 = new AbsoluteDate(leapEnd, dt, utc);
            Assert.assertTrue(FastMath.abs(d1.durationFrom(d2)) < 1.0e-10);
            if (dt < 0) {
                Assert.assertTrue(FastMath.abs(d2.durationFrom(d3)) < 1.0e-10);
                Assert.assertTrue(d4.durationFrom(d5) > (1.0 - 1.0e-10));
            } else {
                Assert.assertTrue(d2.durationFrom(d3) < (-1.0 + 1.0e-10));
                Assert.assertTrue(FastMath.abs(d4.durationFrom(d5)) < 1.0e-10);
            }
        }
    }

    @Test
    public void testSymmetry() {
        final TimeScale tai = TimeScalesFactory.getTAI();
        AbsoluteDate leapStart = new AbsoluteDate(1977, 1, 1, 0, 0, 14, tai);
        for (int i = -10; i < 10; ++i) {
            final double dt = 1.1 * (2 * i - 1);
            Assert.assertEquals(dt, new AbsoluteDate(leapStart, dt, utc).offsetFrom(leapStart, utc), 1.0e-10);
            Assert.assertEquals(dt, new AbsoluteDate(leapStart, dt, tai).offsetFrom(leapStart, tai), 1.0e-10);
            Assert.assertEquals(dt, leapStart.shiftedBy(dt).durationFrom(leapStart), 1.0e-10);
        }
    }

    @Test
    public void testEquals() {
        AbsoluteDate d1 = new AbsoluteDate(new DateComponents(2006, 2, 25), new TimeComponents(17, 10, 34), utc);
        AbsoluteDate d2 = new AbsoluteDate(new DateComponents(2006, 2, 25), new TimeComponents(17, 10, 0), utc)
                .shiftedBy(34);
        Assert.assertTrue(d1.equals(d2));
        Assert.assertFalse(d1.equals(this));
    }

    @Test
    public void testComponents() throws OrekitException {
        // this is NOT J2000.0,
        // it is either a few seconds before or after depending on time scale
        DateComponents date = new DateComponents(2000, 01, 01);
        TimeComponents time = new TimeComponents(11, 59, 10);
        TimeScale[] scales = { TimeScalesFactory.getTAI(), TimeScalesFactory.getUTC(), TimeScalesFactory.getTT(),
                TimeScalesFactory.getTCG() };
        for (int i = 0; i < scales.length; ++i) {
            AbsoluteDate in = new AbsoluteDate(date, time, scales[i]);
            for (int j = 0; j < scales.length; ++j) {
                DateTimeComponents pair = in.getComponents(scales[j]);
                if (i == j) {
                    Assert.assertEquals(date, pair.getDate());
                    Assert.assertEquals(time, pair.getTime());
                } else {
                    Assert.assertNotSame(date, pair.getDate());
                    Assert.assertNotSame(time, pair.getTime());
                }
            }
        }
    }

    @Test
    public void testMonth() throws OrekitException {
        TimeScale utc = TimeScalesFactory.getUTC();
        Assert.assertEquals(new AbsoluteDate(2011, 2, 23, utc), new AbsoluteDate(2011, Month.FEBRUARY, 23, utc));
        Assert.assertEquals(new AbsoluteDate(2011, 2, 23, 1, 2, 3.4, utc),
                new AbsoluteDate(2011, Month.FEBRUARY, 23, 1, 2, 3.4, utc));
    }

    @Test
    public void testCCSDSUnsegmentedNoExtension() throws OrekitException {

        AbsoluteDate reference = new AbsoluteDate("2002-05-23T12:34:56.789", utc);
        double lsb = FastMath.pow(2.0, -24);

        byte[] timeCCSDSEpoch = new byte[] { 0x53, 0x7F, 0x40, -0x70, -0x37, -0x05, -0x19 };
        for (int preamble = 0x00; preamble < 0x80; ++preamble) {
            if (preamble == 0x1F) {
                // using CCSDS reference epoch
                AbsoluteDate ccsds1 = AbsoluteDate.parseCCSDSUnsegmentedTimeCode((byte) preamble, (byte) 0x0,
                        timeCCSDSEpoch, null);
                Assert.assertEquals(0, ccsds1.durationFrom(reference), lsb / 2);
            } else {
                try {
                    AbsoluteDate.parseCCSDSUnsegmentedTimeCode((byte) preamble, (byte) 0x0, timeCCSDSEpoch, null);
                    Assert.fail("an exception should have been thrown");
                } catch (OrekitException iae) {
                    // expected
                }

            }
        }

        // missing epoch
        byte[] timeJ2000Epoch = new byte[] { 0x04, 0x7E, -0x0B, -0x10, -0x07, 0x16, -0x79 };
        try {
            AbsoluteDate.parseCCSDSUnsegmentedTimeCode((byte) 0x2F, (byte) 0x0, timeJ2000Epoch, null);
            Assert.fail("an exception should have been thrown");
        } catch (OrekitException iae) {
            // expected
        }

        // using J2000.0 epoch
        AbsoluteDate ccsds3 = AbsoluteDate.parseCCSDSUnsegmentedTimeCode((byte) 0x2F, (byte) 0x0, timeJ2000Epoch,
                AbsoluteDate.J2000_EPOCH);
        Assert.assertEquals(0, ccsds3.durationFrom(reference), lsb / 2);

    }

    @Test
    public void testCCSDSUnsegmentedWithExtendedPreamble() throws OrekitException {

        AbsoluteDate reference = new AbsoluteDate("2095-03-03T22:02:45.789012345678901", utc);
        int leap = (int) FastMath.rint(utc.offsetFromTAI(reference));
        double lsb = FastMath.pow(2.0, -48);

        byte extendedPreamble = (byte) -0x80;
        byte identification = (byte) 0x10;
        byte coarseLength1 = (byte) 0x0C; // four (3 + 1) bytes
        byte fineLength1 = (byte) 0x03; // 3 bytes
        byte coarseLength2 = (byte) 0x20; // 1 additional byte for coarse time
        byte fineLength2 = (byte) 0x0C; // 3 additional bytes for fine time
        byte[] timeCCSDSEpoch = new byte[] { 0x01, 0x02, 0x03, 0x04, (byte) (0x05 - leap), // 5 bytes for coarse time (seconds)
                -0x37, -0x04, -0x4A, -0x74, -0x2C, -0x3C // 6 bytes for fine time (sub-seconds)
        };
        byte preamble1 = (byte) (extendedPreamble | identification | coarseLength1 | fineLength1);
        byte preamble2 = (byte) (coarseLength2 | fineLength2);
        AbsoluteDate ccsds1 = AbsoluteDate.parseCCSDSUnsegmentedTimeCode(preamble1, preamble2, timeCCSDSEpoch,
                null);
        Assert.assertEquals(0, ccsds1.durationFrom(reference), lsb / 2);

    }

    @Test
    public void testCCSDSDaySegmented() throws OrekitException {

        AbsoluteDate reference = new AbsoluteDate("2002-05-23T12:34:56.789012345678", TimeScalesFactory.getUTC());
        double lsb = 1.0e-13;
        byte[] timeCCSDSEpoch = new byte[] { 0x3F, 0x55, 0x02, -0x4D, 0x2C, -0x6B, 0x00, -0x44, 0x61, 0x4E };

        for (int preamble = 0x00; preamble < 0x100; ++preamble) {
            if (preamble == 0x42) {
                // using CCSDS reference epoch
                AbsoluteDate ccsds1 = AbsoluteDate.parseCCSDSDaySegmentedTimeCode((byte) preamble, timeCCSDSEpoch,
                        null);
                Assert.assertEquals(0, ccsds1.durationFrom(reference), lsb / 2);
            } else {
                try {
                    AbsoluteDate.parseCCSDSDaySegmentedTimeCode((byte) preamble, timeCCSDSEpoch, null);
                    Assert.fail("an exception should have been thrown");
                } catch (OrekitException iae) {
                    // expected
                }

            }
        }

        // missing epoch
        byte[] timeJ2000Epoch = new byte[] { 0x03, 0x69, 0x02, -0x4D, 0x2C, -0x6B, 0x00, -0x44, 0x61, 0x4E };
        try {
            AbsoluteDate.parseCCSDSDaySegmentedTimeCode((byte) 0x4A, timeJ2000Epoch, null);
            Assert.fail("an exception should have been thrown");
        } catch (OrekitException iae) {
            // expected
        }

        // using J2000.0 epoch
        AbsoluteDate ccsds3 = AbsoluteDate.parseCCSDSDaySegmentedTimeCode((byte) 0x4A, timeJ2000Epoch,
                DateComponents.J2000_EPOCH);
        Assert.assertEquals(0, ccsds3.durationFrom(reference), lsb / 2);

        // limit to microsecond
        byte[] timeMicrosecond = new byte[] { 0x03, 0x69, 0x02, -0x4D, 0x2C, -0x6B, 0x00, 0x0C };
        AbsoluteDate ccsds4 = AbsoluteDate.parseCCSDSDaySegmentedTimeCode((byte) 0x49, timeMicrosecond,
                DateComponents.J2000_EPOCH);
        Assert.assertEquals(-0.345678e-6, ccsds4.durationFrom(reference), lsb / 2);

    }

    @Test
    public void testCCSDSCalendarSegmented() throws OrekitException {

        AbsoluteDate reference = new AbsoluteDate("2002-05-23T12:34:56.789012345678", TimeScalesFactory.getUTC());
        double lsb = 1.0e-13;

        // month of year / day of month variation
        byte[] timeMonthDay = new byte[] { 0x07, -0x2E, 0x05, 0x17, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C, 0x22, 0x38,
                0x4E };
        for (int preamble = 0x00; preamble < 0x100; ++preamble) {
            if (preamble == 0x56) {
                AbsoluteDate ccsds1 = AbsoluteDate.parseCCSDSCalendarSegmentedTimeCode((byte) preamble,
                        timeMonthDay);
                Assert.assertEquals(0, ccsds1.durationFrom(reference), lsb / 2);
            } else {
                try {
                    AbsoluteDate.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeMonthDay);
                    Assert.fail("an exception should have been thrown");
                } catch (OrekitException iae) {
                    // expected
                } catch (IllegalArgumentException iae) {
                    // should happen when preamble specifies day of year variation
                    // since there is no day 1303 (= 5 * 256 + 23) in any year ...
                    Assert.assertEquals(preamble & 0x08, 0x08);
                }

            }
        }

        // day of year variation
        byte[] timeDay = new byte[] { 0x07, -0x2E, 0x00, -0x71, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C, 0x22, 0x38,
                0x4E };
        for (int preamble = 0x00; preamble < 0x100; ++preamble) {
            if (preamble == 0x5E) {
                AbsoluteDate ccsds1 = AbsoluteDate.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeDay);
                Assert.assertEquals(0, ccsds1.durationFrom(reference), lsb / 2);
            } else {
                try {
                    AbsoluteDate.parseCCSDSCalendarSegmentedTimeCode((byte) preamble, timeDay);
                    Assert.fail("an exception should have been thrown");
                } catch (OrekitException iae) {
                    // expected
                } catch (IllegalArgumentException iae) {
                    // should happen when preamble specifies month of year / day of month variation
                    // since there is no month 0 in any year ...
                    Assert.assertEquals(preamble & 0x08, 0x00);
                }

            }
        }

        // limit to microsecond
        byte[] timeMicrosecond = new byte[] { 0x07, -0x2E, 0x00, -0x71, 0x0C, 0x22, 0x38, 0x4E, 0x5A, 0x0C };
        AbsoluteDate ccsds4 = AbsoluteDate.parseCCSDSCalendarSegmentedTimeCode((byte) 0x5B, timeMicrosecond);
        Assert.assertEquals(-0.345678e-6, ccsds4.durationFrom(reference), lsb / 2);

    }

    @Test(expected = IllegalArgumentException.class)
    public void testExpandedConstructors() throws OrekitException {
        Assert.assertEquals(
                new AbsoluteDate(new DateComponents(2002, 05, 28), new TimeComponents(15, 30, 0),
                        TimeScalesFactory.getUTC()),
                new AbsoluteDate(2002, 05, 28, 15, 30, 0, TimeScalesFactory.getUTC()));
        Assert.assertEquals(
                new AbsoluteDate(new DateComponents(2002, 05, 28), TimeComponents.H00, TimeScalesFactory.getUTC()),
                new AbsoluteDate(2002, 05, 28, TimeScalesFactory.getUTC()));
        new AbsoluteDate(2002, 05, 28, 25, 30, 0, TimeScalesFactory.getUTC());
    }

    @Test
    public void testHashcode() {
        AbsoluteDate d1 = new AbsoluteDate(new DateComponents(2006, 2, 25), new TimeComponents(17, 10, 34), utc);
        AbsoluteDate d2 = new AbsoluteDate(new DateComponents(2006, 2, 25), new TimeComponents(17, 10, 0), utc)
                .shiftedBy(34);
        Assert.assertEquals(d1.hashCode(), d2.hashCode());
        Assert.assertTrue(d1.hashCode() != d1.shiftedBy(1.0e-3).hashCode());
    }

    @Test
    public void testInfinity() {
        Assert.assertTrue(AbsoluteDate.JULIAN_EPOCH.compareTo(AbsoluteDate.PAST_INFINITY) > 0);
        Assert.assertTrue(AbsoluteDate.JULIAN_EPOCH.compareTo(AbsoluteDate.FUTURE_INFINITY) < 0);
        Assert.assertTrue(AbsoluteDate.J2000_EPOCH.compareTo(AbsoluteDate.PAST_INFINITY) > 0);
        Assert.assertTrue(AbsoluteDate.J2000_EPOCH.compareTo(AbsoluteDate.FUTURE_INFINITY) < 0);
        Assert.assertTrue(AbsoluteDate.PAST_INFINITY.compareTo(AbsoluteDate.JULIAN_EPOCH) < 0);
        Assert.assertTrue(AbsoluteDate.PAST_INFINITY.compareTo(AbsoluteDate.J2000_EPOCH) < 0);
        Assert.assertTrue(AbsoluteDate.PAST_INFINITY.compareTo(AbsoluteDate.FUTURE_INFINITY) < 0);
        Assert.assertTrue(AbsoluteDate.FUTURE_INFINITY.compareTo(AbsoluteDate.JULIAN_EPOCH) > 0);
        Assert.assertTrue(AbsoluteDate.FUTURE_INFINITY.compareTo(AbsoluteDate.J2000_EPOCH) > 0);
        Assert.assertTrue(AbsoluteDate.FUTURE_INFINITY.compareTo(AbsoluteDate.PAST_INFINITY) > 0);
        Assert.assertTrue(Double.isInfinite(AbsoluteDate.FUTURE_INFINITY.durationFrom(AbsoluteDate.J2000_EPOCH)));
        Assert.assertTrue(Double.isInfinite(AbsoluteDate.FUTURE_INFINITY.durationFrom(AbsoluteDate.PAST_INFINITY)));
        Assert.assertTrue(Double.isInfinite(AbsoluteDate.PAST_INFINITY.durationFrom(AbsoluteDate.J2000_EPOCH)));
    }

    @Test
    public void testAccuracy() {
        TimeScale tai = TimeScalesFactory.getTAI();
        double sec = 0.281;
        AbsoluteDate t = new AbsoluteDate(2010, 6, 21, 18, 42, sec, tai);
        double recomputedSec = t.getComponents(tai).getTime().getSecond();
        Assert.assertEquals(sec, recomputedSec, FastMath.ulp(sec));
    }

    @Test
    public void testIterationAccuracy() {

        final TimeScale tai = TimeScalesFactory.getTAI();
        final AbsoluteDate t0 = new AbsoluteDate(2010, 6, 21, 18, 42, 0.281, tai);

        // 0.1 is not representable exactly in double precision
        // we will accumulate error, between -0.5ULP and -3ULP at each iteration
        checkIteration(0.1, t0, 10000, 3.0, -1.19, 1.0e-4);

        // 0.125 is representable exactly in double precision
        // error will be null
        checkIteration(0.125, t0, 10000, 1.0e-15, 0.0, 1.0e-15);

    }

    private void checkIteration(final double step, final AbsoluteDate t0, final int nMax,
            final double maxErrorFactor, final double expectedMean, final double meanTolerance) {
        final double epsilon = FastMath.ulp(step);
        AbsoluteDate iteratedDate = t0;
        double mean = 0;
        for (int i = 1; i < nMax; ++i) {
            iteratedDate = iteratedDate.shiftedBy(step);
            AbsoluteDate directDate = t0.shiftedBy(i * step);
            final double error = iteratedDate.durationFrom(directDate);
            mean += error / (i * epsilon);
            Assert.assertEquals(0.0, iteratedDate.durationFrom(directDate), maxErrorFactor * i * epsilon);
        }
        mean /= nMax;
        Assert.assertEquals(expectedMean, mean, meanTolerance);
    }

    @Test
    public void testIssue142() throws OrekitException {

        final AbsoluteDate epoch = AbsoluteDate.JAVA_EPOCH;
        final TimeScale utc = TimeScalesFactory.getUTC();

        Assert.assertEquals("1970-01-01T00:00:00.000", epoch.toString(utc));
        Assert.assertEquals(0.0, epoch.durationFrom(new AbsoluteDate(1970, 1, 1, utc)), 1.0e-15);
        Assert.assertEquals(8.000082,
                epoch.durationFrom(new AbsoluteDate(DateComponents.JAVA_EPOCH, TimeScalesFactory.getTAI())),
                1.0e-15);

        //Milliseconds - April 1, 2006, in UTC
        long msOffset = 1143849600000l;
        final AbsoluteDate ad = new AbsoluteDate(epoch, msOffset / 1000, TimeScalesFactory.getUTC());
        Assert.assertEquals("2006-04-01T00:00:00.000", ad.toString(utc));

    }

    @Test
    public void testIssue148() throws OrekitException {
        final TimeScale utc = TimeScalesFactory.getUTC();
        AbsoluteDate t0 = new AbsoluteDate(2012, 6, 30, 23, 59, 50.0, utc);
        DateTimeComponents components = t0.shiftedBy(11.0 - 200 * Precision.EPSILON).getComponents(utc);
        Assert.assertEquals(2012, components.getDate().getYear());
        Assert.assertEquals(6, components.getDate().getMonth());
        Assert.assertEquals(30, components.getDate().getDay());
        Assert.assertEquals(23, components.getTime().getHour());
        Assert.assertEquals(59, components.getTime().getMinute());
        Assert.assertEquals(61 - 200 * Precision.EPSILON, components.getTime().getSecond(), 1.0e-15);
    }

    @Test
    public void testIssue149() throws OrekitException {
        final TimeScale utc = TimeScalesFactory.getUTC();
        AbsoluteDate t0 = new AbsoluteDate(2012, 6, 30, 23, 59, 59, utc);
        DateTimeComponents components = t0.shiftedBy(1.0 - Precision.EPSILON).getComponents(utc);
        Assert.assertEquals(2012, components.getDate().getYear());
        Assert.assertEquals(6, components.getDate().getMonth());
        Assert.assertEquals(30, components.getDate().getDay());
        Assert.assertEquals(23, components.getTime().getHour());
        Assert.assertEquals(59, components.getTime().getMinute());
        Assert.assertEquals(60 - Precision.EPSILON, components.getTime().getSecond(), 1.0e-15);
    }

    @Before
    public void setUp() throws OrekitException {
        Utils.setDataRoot("regular-data");
        utc = TimeScalesFactory.getUTC();
    }

    private TimeScale utc;

}