/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.brooklyn.util.time;
import java.util.Date;
import java.util.TimeZone;
import org.apache.brooklyn.util.time.Duration;
import org.apache.brooklyn.util.time.Time;
import org.testng.Assert;
import org.testng.annotations.Test;
@Test
public class TimeTest {
public void testMakeStringExact_secondsAndMillis() {
check(1, "1ms");
check(1000, "1s");
check(1001, "1s 1ms");
check(1011, "1s 11ms");
check(3*1000, "3s");
check(3*1000+1, "3s 1ms");
check(3*1000+10, "3s 10ms");
check(3*1000+100, "3s 100ms");
check(30*1000, "30s");
check(30*1000+1, "30s 1ms");
check(30*1000+100, "30s 100ms");
}
public void testMakeStringRounded_secondsAndMillis() {
checkR(1, "1ms");
checkR(1000, "1s");
checkR(1001, "1.00s");
checkR(1011, "1.01s");
checkR(3*1000, "3s");
checkR(3*1000+1, "3.00s");
checkR(3*1000+10, "3.01s");
checkR(3*1000+100, "3.10s");
checkR(30*1000, "30s");
checkR(30*1000+1, "30.0s");
checkR(30*1000+10, "30.0s");
checkR(30*1000+100, "30.1s");
}
public void testMakeStringExact_days() {
check(3*Time.MILLIS_IN_DAY, "3d");
check(3*Time.MILLIS_IN_DAY + 2*Time.MILLIS_IN_HOUR + 30*Time.MILLIS_IN_MINUTE + 1001, "3d 2h 30m 1s 1ms");
}
public void testMakeStringRounded_days() {
checkR(3*Time.MILLIS_IN_DAY, "3d");
checkR(3*Time.MILLIS_IN_DAY + 2*Time.MILLIS_IN_HOUR + 30*Time.MILLIS_IN_MINUTE + 1001, "3d 2h");
checkR(3*Time.MILLIS_IN_DAY + 30*Time.MILLIS_IN_MINUTE + 1001, "3d 30m");
checkR(3*Time.MILLIS_IN_DAY + 1001, "3d");
checkR(30*Time.MILLIS_IN_MINUTE + 1111, "30m 1s");
}
public void testMakeStringExact_nanos() {
checkN(1001, "1us 1ns");
checkN(123000+456, "123us 456ns");
checkN(3*Time.MILLIS_IN_DAY*1000*1000, "3d");
checkN(3*Time.MILLIS_IN_DAY*1000*1000 + 1, "3d 1ns");
checkN(3*Time.MILLIS_IN_DAY*1000*1000 + 1001, "3d 1us 1ns");
checkN((3*Time.MILLIS_IN_DAY + 2*Time.MILLIS_IN_HOUR + 30*Time.MILLIS_IN_MINUTE + 1001)*1000*1000+123000+456,
"3d 2h 30m 1s 1ms 123us 456ns");
}
public void testMakeStringRounded_nanos() {
checkRN(3*Time.MILLIS_IN_DAY*1000*1000, "3d");
checkRN((3*Time.MILLIS_IN_DAY + 2*Time.MILLIS_IN_HOUR + 30*Time.MILLIS_IN_MINUTE + 1001)*1000*1000+1001, "3d 2h");
checkRN((3*Time.MILLIS_IN_DAY + 30*Time.MILLIS_IN_MINUTE + 1001)*1000*1000+1001, "3d 30m");
checkRN((3*Time.MILLIS_IN_DAY + 1001)*1000*1000+1001, "3d");
checkRN((30*Time.MILLIS_IN_MINUTE + 1111)*1000*1000+1001, "30m 1s");
checkRN((30*Time.MILLIS_IN_MINUTE)*1000*1000+1001, "30m");
checkRN((31000L)*1000*1000, "31s");
checkRN((31000L)*1000*1000+1001, "31.0s");
checkRN(1001, "1.001us");
checkRN(10101, "10.10us");
checkRN(101001, "101.0us");
checkRN(123000+456, "123.5us");
}
private void check(long millis, String expected) {
Assert.assertEquals(Time.makeTimeStringExact(millis), expected);
}
private void checkR(long millis, String expected) {
Assert.assertEquals(Time.makeTimeStringRounded(millis), expected);
}
private void checkN(long nanos, String expected) {
Assert.assertEquals(Time.makeTimeStringNanoExact(nanos), expected);
}
private void checkRN(long nanos, String expected) {
Assert.assertEquals(Time.makeTimeStringNanoRounded(nanos), expected);
}
@Test
public void testDateRounding() {
long x = System.currentTimeMillis();
Date d1 = Time.dropMilliseconds(new Date(x));
Date d2 = new Date(x - (x%1000));
Date d3 = new Date( (x/1000)*1000 );
Assert.assertEquals(d1.getTime() % 1000, 0);
Assert.assertEquals(d1, d2);
Assert.assertEquals(d1, d3);
}
@Test
public void testDateRoundingNull() {
Assert.assertNull(Time.dropMilliseconds(null));
}
@Test
public void testMakeStringExactZero() { check(0, "0ms"); }
@Test
public void testMakeStringExactNegative() { check(-1, "-1ms"); }
@Test
public void testMakeStringRoundedZero() { checkR(0, "0ms"); }
@Test
public void testMakeStringRoundedNegative() { checkR(-1, "-1ms"); }
@Test
public void testElapsedSince() {
long aFewSecondsAgo = System.currentTimeMillis() - 7*1000;
Duration aFewSeconds = Time.elapsedSince(aFewSecondsAgo);
Assert.assertTrue(aFewSeconds.toMilliseconds() > 5*1000);
Assert.assertTrue(10*1000 > aFewSeconds.toMilliseconds());
Assert.assertTrue(Time.hasElapsedSince(aFewSecondsAgo, Duration.FIVE_SECONDS));
Assert.assertFalse(Time.hasElapsedSince(aFewSecondsAgo, Duration.TEN_SECONDS));
Assert.assertTrue(Time.hasElapsedSince(-1, Duration.TEN_SECONDS));
}
@Test
public void testParseTime() {
Assert.assertEquals(Time.parseElapsedTime("1s"), 1000);
Assert.assertEquals(Time.parseElapsedTime("never"), -1);
}
@Test
public void testMakeDateString() {
String in1 = "2015-06-15T12:34:56";
Date d1 = Time.parseDate(in1);
Assert.assertEquals(Time.makeDateString(d1), in1.replace('T', ' ')+".000");
String in2 = "2015-06-15T12:34:56Z";
Date d2 = Time.parseDate(in2);
Assert.assertEquals(Time.makeDateString(d2, Time.DATE_FORMAT_ISO8601, Time.getTimeZone("UTC")), in1+".000+0000");
}
@Test(groups="Integration") //because it depends on TZ's set up and parsing months
public void testTimeZones() {
// useful to debug, if new special time zones needed
// for (String id: TimeZone.getAvailableIDs()) {
// TimeZone tz = TimeZone.getTimeZone(id);
// System.out.println(id+": "+tz.getDisplayName()+" "+tz.getDisplayName(true, TimeZone.SHORT)+" "+tz);
// }
Assert.assertEquals("+0100", Time.getTimeZoneOffsetString("Europe/London", 2015, 6, 4).get());
Assert.assertEquals("-0500", Time.getTimeZoneOffsetString("EST", 2015, 1, 4).get());
Assert.assertEquals("-0400", Time.getTimeZoneOffsetString("America/New_York", 2015, 6, 4).get());
Assert.assertEquals("-0500", Time.getTimeZoneOffsetString("America/New_York", 2015, 1, 4).get());
// BST treated as British Time (not Bangladesh)
Assert.assertEquals("+0000", Time.getTimeZoneOffsetString("BST", 2015, 1, 4).get());
Assert.assertEquals("+0100", Time.getTimeZoneOffsetString("BST", 2015, 6, 4).get());
// EST treated as EDT not fixed -0500
Assert.assertEquals("-0400", Time.getTimeZoneOffsetString("EST", 2015, 6, 4).get());
// these normally not recognized
Assert.assertEquals("-0400", Time.getTimeZoneOffsetString("EDT", 2015, 6, 4).get());
Assert.assertEquals("-0500", Time.getTimeZoneOffsetString("EDT", 2015, 1, 4).get());
Assert.assertEquals("-0600", Time.getTimeZoneOffsetString("CST", 2015, 1, 4).get());
Assert.assertEquals("-0700", Time.getTimeZoneOffsetString("MST", 2015, 1, 4).get());
Assert.assertEquals("-0800", Time.getTimeZoneOffsetString("PST", 2015, 1, 4).get());
Assert.assertEquals("+0530", Time.getTimeZoneOffsetString("IST", 2015, 1, 4).get());
}
@Test
public void testParseDate() {
doTestParseDate(false);
}
@Test(groups="Integration") //because it depends on TZ's set up and parsing months
public void testParseDateIntegration() {
doTestParseDate(true);
}
private void doTestParseDate(boolean integration) {
// explicit TZ inclusion
assertDatesParseToEqual("2015.6.4.0000 +0100", "2015-06-04-0000 +0100");
assertDatesParseToEqual("2015.6.4.0100 +0100", "2015-06-04-0000 +0000");
assertDatesParseToEqual("2015.6.4.0100 -0100", "2015-06-04-0200 +0000");
if (integration) assertDatesParseToEqual("20150604 BST", "2015-06-04 +0100");
// no TZ uses server default
assertDatesParseToEqual("2015.6.4.0000", "2015-06-04-0000 "+Time.getTimeZoneOffsetString(TimeZone.getDefault(), 2015, 6, 4));
assertDatesParseToEqual("20150604", "2015-06-04-0000");
// parse TZ
if (integration) {
assertDatesParseToEqual("20150604 +BST", "2015-06-04 +0100");
assertDatesParseToEqual("20150604 - - - BST", "2015-06-04 +0100");
assertDatesParseToEqual("20150604--BST", "2015-06-04 +0100");
assertDatesParseToEqual("20150604-//-BST", "2015-06-04 +0100");
}
assertDatesParseToEqual("2015.6.4+0100", "2015-06-04-0000+0100");
assertDatesParseToEqual("20150604-+0100", "2015-06-04 +0100");
assertDatesParseToEqual("20150604, +0100", "2015-06-04 +0100");
assertDatesParseToEqual("201506040000, 0100", "2015-06-04 +0100");
assertDatesParseToEqual("20150604 , 0000 , 0100", "2015-06-04 +0100");
assertDatesParseToEqual("2015-6-4 +0100", "2015-06-04-0000 +0100");
assertDatesParseToEqual("2015-6-4 -0100", "2015-06-04-0000 -0100");
assertDatesParseToEqual("20150604-0000//-0100", "2015-06-04 -0100");
// ambiguous TZ/hours parse prefers hours
assertDatesParseToEqual("2015-6-4-0100", "2015-06-04-0100");
assertDatesParseToEqual("2015-6-4--0100", "2015-06-04-0100");
// formats without spaces
assertDatesParseToEqual("20150604080012", "2015-06-04-080012");
assertDatesParseToEqual("20150604080012 +1000", "2015-06-03-220012 +0000");
assertDatesParseToEqual("20150604080012 -1000", "2015-06-04-180012 +0000");
assertDatesParseToEqual("20150604080012.345 +1000", "2015-06-03-220012.345 +0000");
if (integration) {
assertDatesParseToEqual("20150604 BST", "2015-06-04 +0100");
assertDatesParseToEqual("20150604 Europe/London", "2015-06-04 +0100");
}
// more misc tests
assertDatesParseToEqual("20150604 08:00:12.345", "2015-06-04-080012.345");
assertDatesParseToEqual("20150604-080012.345", "2015-06-04-080012.345");
assertDatesParseToEqual("2015-12-1", "2015-12-01-0000");
assertDatesParseToEqual("1066-12-1", "1066-12-01-0000");
assertDatesParseToEqual("20150604T080012.345", "2015-06-04-080012.345");
assertDatesParseToEqual("20150604T080012.345Z", "2015-06-04-080012.345+0000");
assertDatesParseToEqual("20150604t080012.345 Z", "2015-06-04-080012.345+0000");
// millis parse, and zero is epoch, but numbers which look like a date or datetime take priority
assertDatesParseToEqual("0", "1970-1-1 UTC");
assertDatesParseToEqual("20150604", "2015-06-04");
assertDatesParseToEqual(""+Time.parseDate("20150604").getTime(), "2015-06-04");
assertDatesParseToEqual("20150604080012", "2015-06-04-080012");
assertDatesParseToEqual("0", "1970-1-1 UTC");
// leap year
Assert.assertEquals(Time.parseDate("2012-2-29").getTime(), Time.parseDate("2012-3-1").getTime() - 24*60*60*1000);
// perverse, but accepted for the time being:
Assert.assertEquals(Time.parseDate("2013-2-29").getTime(), Time.parseDate("2013-3-1").getTime());
// accept am and pm
assertDatesParseToEqual("20150604 08:00:12.345a", "2015-06-04-080012.345");
assertDatesParseToEqual("20150604 08:00:12.345 PM", "2015-06-04-200012.345");
if (integration) assertDatesParseToEqual("20150604 08:00:12.345 am BST", "2015-06-04-080012.345 +0100");
// *calendar* parse includes time zone
Assert.assertEquals(Time.makeDateString(Time.parseCalendar("20150604 08:00:12.345a +0100"),
Time.DATE_FORMAT_ISO8601), "2015-06-04T08:00:12.345+0100");
Assert.assertEquals(Time.makeDateString(Time.parseCalendar("20150604 08:00:12.345a "+Time.TIME_ZONE_UTC.getID()),
Time.DATE_FORMAT_ISO8601), "2015-06-04T08:00:12.345+0000");
// accept month in words
if (integration) {
assertDatesParseToEqual("2015-Dec-1", "2015-12-01-0000");
assertDatesParseToEqual("2015 Dec 1", "2015-12-01-0000");
assertDatesParseToEqual("2015-DEC-1", "2015-12-01-0000");
assertDatesParseToEqual("2015 December 1", "2015-12-01-0000");
assertDatesParseToEqual("2015 December 1", "2015-12-01-0000");
assertDatesParseToEqual("2015-Mar-1", "2015-03-01-0000");
assertDatesParseToEqual("2015 Mar 1", "2015-03-01-0000");
assertDatesParseToEqual("2015-MAR-1", "2015-03-01-0000");
assertDatesParseToEqual("2015 March 1", "2015-03-01-0000");
assertDatesParseToEqual("2015 March 1", "2015-03-01-0000");
}
// for month in words, allow selected other orders also
if (integration) {
assertDatesParseToEqual("1-Jun-2015", "2015-06-01-0000");
assertDatesParseToEqual("Jun 1, 2015", "2015-06-01-0000");
assertDatesParseToEqual("June 1, 2015, 4pm", "2015-06-01-1600");
}
// also allow time first if separators are used
assertDatesParseToEqual("16:00, 2015-12-30", "2015-12-30-1600");
if (integration) {
assertDatesParseToEqual("4pm, Dec 1, 2015", "2015-12-01-1600");
assertDatesParseToEqual("16:00 30-Dec-2015", "2015-12-30-1600");
}
// and if time comes first, TZ can be before or after date
assertDatesParseToEqual("4pm +0100, 2015-12-30", "2015-12-30-1600 +0100");
assertDatesParseToEqual("4pm, 2015-12-30, +0100", "2015-12-30-1600 +0100");
// these ambiguous ones are accepted (maybe we'd rather not),
// but they are interpreted sensibly, preferring the more sensible interpretation
if (integration) assertDatesParseToEqual("16 Dec 1 2015", "2015-12-01-1600");
if (integration) assertDatesParseToEqual("16:30 1067 Dec 1 1066", "1067-12-01-1630 +1066");
assertDatesParseToEqual("1040 1045 12 1", "1045-12-01-1040");
assertDatesParseToEqual("1040 1045 12 1 +0", "1045-12-01-1040Z");
if (integration) assertDatesParseToEqual("1045 Dec 1 1040", "1045-12-01-1040");
if (integration) assertDatesParseToEqual("10:40 Dec 1 1045", "1045-12-01-1040");
assertDatesParseToEqual("10.11-2020-12.01", "2020-12-01-1011");
if (integration) assertDatesParseToEqual("Oct.11 1045 12.01", "1045-10-11-1201");
if (integration) assertDatesParseToEqual("1040 1045 Dec 1 1030", "1045-12-01-1040 +1030");
assertDatesParseToEqual("1040 +02 2015 12 1", "2015-12-01-1040 +0200");
assertDatesParseToEqual("10:40:+02 2015 12 1", "2015-12-01-1040 +0200");
}
@Test
public void testParseDateToStringWithMillisecond() {
Date d = new Date();
// clear seconds, but add a milli - to ensure not just toString formatting but also seconds computation
d.setTime(d.getTime() - (d.getTime() % 60000) + 1);
assertDatesParseToEqual(d.toString(), Time.makeDateStampString(d.getTime()));
}
private void assertDatesParseToEqual(String input, String expected) {
Assert.assertEquals(Time.parseDate(input).toString(), Time.parseDate(expected).toString(), "for: "+input+" ("+expected+")");
}
}