0

I'm no expert programmer, but I have looked online for a solution to this and cannot find anything to help me.

Here is what I am trying to do for an automation project at work. I am being given a time value in milliseconds. I need to take that time value, add 6 minutes to it, then retrieve the hour, minutes, and AM_PM value so I can then do my test.

The problem is that after I retrieve the time, I then set it with a CALENDAR, do the addition, and when I go to retrieve the minutes and hours, they are not set correctly.

For example, here is my code:

    _logger.info("Get current system time in milliseconds");
    long currentTime = TimeApi.getCurrentSystemTime(_deviceUnderTestPIN);
    _logger.info("Current device time is : " + Long.toString(currentTime));

    _logger.info("Set Calendar object with device time");
    Calendar now = Calendar.getInstance();
    now.setTimeInMillis(currentTime);

    long timeSet = now.getTimeInMillis();
    _logger.info("Calendar object is set to : " + Long.toString(timeSet));

    _logger.info("add mintuesToAdd to current time");
    now.add(Calendar.MINUTE, minutesToAdd);

    long timeAdd = now.getTimeInMillis();
    _logger.info("Calendar Time after Add: " + Long.toString(timeAdd));

    _logger.info("set hour and minute");
    // if the hour is 12am or 12pm the Calendar object will return 0, we need to pass  in 12 so we will set it to 12 below if it returns 0
    hour = now.get(Calendar.HOUR);
    if (hour == 0) {
        hour = 12;
    }
    minutes = now.get(Calendar.MINUTE);

    _logger.info("set amPM");
    if (now.get(Calendar.AM_PM) == 0) {
        amPM = false;
    } else {
        amPM = true;
    }

    _logger.info("Setting alarm hour to: " + Integer.toString(hour));
    _logger.info("Setting the alarm minutes to: " + Integer.toString(minutes));
    _logger.info("Setting alarm AM_PM to: " + Boolean.toString(amPM));

And here is the output from my test run:

2013-06-06  13:15:36.007  INFO Current device time is : 1370524535000
2013-06-06  13:15:36.007  INFO Set Calendar object with device time
2013-06-06  13:15:36.007  INFO Calendar object is set to : 1370524535000
2013-06-06  13:15:36.007  INFO add mintuesToAdd to current time
2013-06-06  13:15:36.007  INFO Calendar Time after Add: 1370524895000
2013-06-06  13:15:36.007  INFO set hour and minute
2013-06-06  13:15:36.007  INFO set amPM
2013-06-06  13:15:36.023  INFO Setting alarm hour to: 1
2013-06-06  13:15:36.023  INFO Setting the alarm minutes to: 21
2013-06-06  13:15:36.023  INFO Setting alarm AM_PM to: true

As you can see the time value I have and are trying to set it Thu Jun 06 2013 09:15:35 GMT-0400 (Eastern Daylight Time). So the part I don't understand is why is it taking the server time when i call now.get(Calendar.HOUR)???

Any help would be greatly appreciated

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
DAC
  • 23
  • 1
  • 3
  • 1
    How do you know the hour is wrong? You never log the value of the calendar before you do your manipulation. Also, you should log the whole calendar instance (i.e. all fields) or use a time formatter to see all fields. Otherwise, roll over effects (i.e. adding 7 minutes to 9:55 will change the hour) will confuse you. – Aaron Digulla Jun 06 '13 at 15:26
  • 1
    `now.add` changes the hour too. Use a `new SimpleDateFormat("HH:mm")` to output the calendar instance. – Joop Eggen Jun 06 '13 at 15:27
  • I'd do the addition in milliseconds ... you can use TimeUnit for convenience. I often get gray hair when using Calendar, so I avoid it ;) – Fildor Jun 06 '13 at 15:30
  • Sorry Im not sure what you mean. I've outputted the time in milliseconds before and after I added the 6 minutes. – DAC Jun 06 '13 at 15:30
  • I want now.add to change the hour if needed. For example if the current time is 11:59AM and I add 6 minutes, then i want a return of 12:05PM. – DAC Jun 06 '13 at 15:32
  • 1
    Looking at the third and fifth line of your output, the value has changed for 6 minutes. What's your question? Also output hours and minutes before adding the time, then you'll see the change. – jlordo Jun 06 '13 at 15:35
  • Ill add the extra output lines, will take me sometime to get results as the issue happens on our server and a run takes 5 hours. The question is why is the hour returning 1, and miniutes 21. The time I set was 9:15 AM (1370524895000) – DAC Jun 06 '13 at 15:40
  • Unixtimestamp.com sais 1370524895000 is 06 / 06 / 13 @ 8:21:35am EST so I guess minutes are correct and hours is due to a wrong timezone. – Fildor Jun 06 '13 at 15:49

2 Answers2

1

I think you need to use the timezome parameter when getting the instance of the Calendar as below:

Calendar now = Calendar.getInstance(TimeZone.getTimeZone("America/New_York"));
Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
  • Makes sense, however I cannot hardcode the timezone as it may change, I need to retrieve it from the value returned to me from TimeApi.getCurrentSystemTime (this method returns the time on the device Im testing, which is not the Server) – DAC Jun 06 '13 at 15:36
  • I thought now.setTimeInMillis(currentTime); would also set the timezone value – DAC Jun 06 '13 at 15:36
  • @user2460213 setTimeInMillis sets the long value in the default timezome. I would advice to retrieve the timezone of the device and explicitely set in the calendar before using it. – Yogendra Singh Jun 06 '13 at 15:38
  • 1
    To quote the JavaDocs, the `setTimeInMillis` takes *the new time in UTC milliseconds from the epoch*. – Nick Holt Jun 06 '13 at 15:40
  • @user2460213 In addition, if you are unable to get the device timezone then I think one alternate option would be to get the different between local time and device time in millis e.g. TimeApi.getCurrentSystemTime(_deviceUnderTestPIN) - new Date().getTime(); and add the same in calendar. – Yogendra Singh Jun 06 '13 at 15:41
  • Thanks i will try that and let you know how it goes – DAC Jun 06 '13 at 15:48
  • I ended up being able to retreieve the timezone from the device after all, so when I did as suggested above my issue was resolved. Thank everyone. – DAC Jun 06 '13 at 19:59
0

tl;dr

Instant.ofEpochMilli( 1_370_524_535_000L )                      // Parse count-of-milliseconds-since-epoch as a `Instant`. 
    .plus( Duration.ofMinutes( 6 ) )                            // Calculate six minutes later.
    .atZone( ZoneId.of( "Asia/Kolkata" ) )                      // Adjust from UTC of a `Instant` to the time zone of a `ZonedDateTime` object.
    .toLocalTime()                                              // Extract the time-of-day, without the date and without the time zone.
    .format(                                                    // Generate a string.
        DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ) // Automatically localize using…
                         .withLocale( Locale.US )               // …the human language and cultural norms of a given locale.
     )

6:51:35 PM

java.time

You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.

If given a count of milliseconds since the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00Z, then parse as a Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Instant instant = Instant.ofEpochMilli( 1_370_524_535_000L ) ;

instant.toString(): 2013-06-06T13:15:35Z

Represent your six minute span of time as a Duration.

Duration d = Duration.ofMinutes( 6 ) ; // Span of time (hours-minutes-seconds) unattached to the timeline.

Do the math.

Instant sixMinutesLater = instant.plus( d ) ; // Add the duration of six minutes to the UTC moment.

Convert to the more flexible OffsetDateTime, to complete our other work.

OffsetDateTime odt = OffsetDateTime.ofInstant( sixMinutesLater , ZoneOffset.UTC ) ;

To get the time of day, without a date and without a time zone, extract a LocalTime.

LocalTime lt = odt.toLocalTime() ;

To ask if it is morning, compare to another LocalTime representing noon, 12:00.

Boolean isBeforeNoon = lt.isBefore( LocalTime.NOON ) ;

You can interrogate for the parts: getHour (0-23), getMinute, and so on.

You may want to generate a string representing this value. Specify a formatting pattern, or automatically localize.

DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( Locale.US ) ;
String output = lt.format( f ) ;

The above code assumes you want to work in UTC. If instead you want the time-of-day as seen on a wall-clock by the people of a certain region, you must specify a time zone (ZoneId) to get a ZonedDateTime object.

ZoneId z = ZoneId.of( "Africa/Tunis" );
ZonedDateTime zdtAfricaTunis = instant.atZone( z );
LocalTime ltAfricaTunis = zdtAfricaTunis.toLocalTime();

Dump to console.

System.out.println( "instant.toString(): " + instant + " and sixMinutesLaterInstant: " + sixMinutesLaterInstant );
System.out.println( "odt.toString(): " + odt + " and lt.toString(): " + lt + " is morning: " + isBeforeNoon + " with output: " + output );
System.out.println( "zdtAfricaTunis.toString(): " + zdtAfricaTunis + " and ltAfricaTunis.toString(): " + ltAfricaTunis );

instant.toString(): 2013-06-06T13:15:35Z and sixMinutesLaterInstant: 2013-06-06T13:21:35Z

odt.toString(): 2013-06-06T13:21:35Z and lt.toString(): 14:21:35 is morning: false with output: 1:21:35 PM

zdtAfricaTunis.toString(): 2013-06-06T14:21:35+01:00[Africa/Tunis] and ltAfricaTunis.toString(): 14:21:35


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154