user7046311
user7046311

Reputation: 71

convert date to epochseconds in java taking consideration of local timezone

I would like to convert a date to epoch range of (12 AM of that day, 11.59 PM GMT of that day).

  1. fromDate=2019-10-25T00:00:00-07:00, toDate=2019-10-25T23:59:59-07:00: would like to return (1571986800,1572073199) (equivalent to timestamp of GMT October 25, 2019 7:00:00 AM , GMT October 26, 2019 6:59:59 AM)
  2. fromDate=2019-10-24T00:00:00-07:00, toDate=2019-10-24T23:59:59-07:00: would like to return (1571900400,1571986799) (equivalent to timestamp of GMT October 24, 2019 7:00:00 AM, GMT October 25, 2019 6:59:59 AM)

My attempt:

fromDate = String.valueOf(formatter.parse(fromDate.substring(0, 19)).toInstant().getEpochSecond());
toDate = String.valueOf(formatter.parse(toDate.substring(0, 19)).toInstant().getEpochSecond());
epochDateRange.append("(").append(fromDate).append(",").append(toDate).append(")");

When debugging by setting to other timezone: i.e. add the following parameter at eclipse - debug configuration

'-Duser.timezone=Asia/Kuala_Lumpur'
  1. For the above timezone, on Oct 25 it returns (1571932800,1572019199) but the result wanted is (1571986800,1572073199)

  2. For the above timezone, on Oct24 it returns (1571846400,1571932799) but the result wanted is (1571900400,1571986799)

Any help will be appreciated. Thanks.

Upvotes: 0

Views: 1013

Answers (2)

Anonymous
Anonymous

Reputation: 86389

Since your strings contain UTC offset, you need to parse that offset to get the correct time.

    String fromDateString = "2019-10-25T00:00:00-07:00";
    long fromEpochSecond = OffsetDateTime.parse(fromDateString).toEpochSecond();
    System.out.println("fromEpochSecond: " + fromEpochSecond);

Output from this snippet is:

fromEpochSecond: 1571986800

This is the Unix timestamp (count of seconds since the epoch) that you asked for. Do similarly with the other strings (you will want to wrap the conversion into a utility method).

Note that this code is independent of any time zone. It simply trusts the offset that is in the string.

A couple of further tips:

  • I suspect that your code uses the old DateFormat and/or SimpleDateFormat class. Don’t do that. Those classes are notoriously troublesome and long outdated. If you need a formatter, use the modern DateTimeFormatter from java.time.
  • Use half-open intervals. Don’t represent the end of day as 23:59:59. Represent the end of the day through the first moment of the next day exclusive. So October 25 would usually end at October 26 00:00:00, and always at the first moment of October 26.
  • If you have a date and a time zone, find the Unix timestamp of the start of the day like this:

        ZoneId zone = ZoneId.of("Asia/Kuala_Lumpur");
        LocalDate date = LocalDate.of(2019, Month.OCTOBER, 25);
        long startOfDayEpochSecond = date.atStartOfDay(zone).toEpochSecond();
        System.out.println("startOfDayEpochSecond: " + startOfDayEpochSecond);
    

    startOfDayEpochSecond: 1571932800

    It’s not the same time as above because Kuala Lumpur is not at offset -07:00. I believe that it is at +08:00.

Upvotes: 0

Basil Bourque
Basil Bourque

Reputation: 340230

Your Question is quite confusing. So I can only guess at what you are trying to do. But the main issue may be that you misunderstand what is a count-from-epoch.

For one thing, there are dozens of epoch reference date-times commonly in use. Always state the one you mean. The date-time classes bundled with Java use the first moment of 1970 in UTC, 1970-01-01T00:00Z.

For another thing, you may not realize how the count-from-epoch must reference an offset or time zone to make any sense. Again, in Java, we use UTC as mentioned above, and as seen in the Z on the end of the string seen above, in standard ISO 8601 format.

Another issue is that you seem to be trying to represent the start and stop of an entire day by nailing down the last moment of the day. That is problematic. In date-time handling we commonly use the half-open approach to defining a span-of-time. In half-open, the beginning is inclusive while the ending is exclusive. So a day starts at its first moment and runs up to, but does not include, the first moment of the following day.

OffsetDateTime start = OffsetDateTime.parse( "2019-10-25T00:00:00-07:00" );
OffsetDateTime stop = start.plusDays( 1 ) ;

start.toString(): 2019-10-25T00:00-07:00

stop.toString(): 2019-10-26T00:00-07:00

Another issue is using 12:00:00 AM. That can be a tricky way to represent rolling over midnight. I suggest sticking with 24-clock for your coding. So the day in UTC always starts at 00:00:00.0. (By the way, the day does not always start at 00:00 in some time zones on some dates.)

Yet another issue is your use of offsets rather than time zone. If you know the time zone is, for example, America/Phoenix, use that rather than an offset of -07:00.

As for your jumping from an offset of -07:00 to GMT, you lost me there. I have no idea what you mean. But perhaps this will help.

If you want to see what 2019-10-25T00:00:00-07:00 is in UTC, simply extract an Instant from your OffsetDateTime. An Instant is always in UTC, by definition.

OffsetDateTime
.parse( "2019-10-25T00:00:00-07:00" )
.toInstant()
.toString() 

2019-10-25T07:00:00Z

So your calling 2019-10-25T00:00:00-07:00 as equivalent to October 25, 2019 12:00:00 AM GMT (GMT and UTC are the same, practically speaking) is nonsensical. The -07:00 on the first string means that the date-time is seven hours behind UTC. So the same date with same time-of-day in UTC cannot possibly represent the same moment.

Perhaps your goal is getting the first moment of the day as seen by the people of some region, a time zone.

ZoneId z = ZoneId.of( "Asia/Kuala_Lumpur" ) ;
LocalDate ld = LocalDate.parse( "2019-10-25" ) ;
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
ZonedDateTime zdtStop = zdtStart.plusDays( 1 ) ;

See that start and stop when adjusted to UTC.

Instant utcStart = zdtStart.toInstant() ;
Instant utcStop = zdtStop.toInstant() ;

Get the count-from-epoch 1970-01-01T00:00:00Z with granularity of whole seconds.

long secondsSinceEpochStart = utcStart.getEpochSecond() ;
long secondsSinceEpochStop = utcStop.getEpochSecond() ;

zdtStart/zdtStop: 2019-10-25T00:00+08:00[Asia/Kuala_Lumpur]/2019-10-26T00:00+08:00[Asia/Kuala_Lumpur]

utcStart/utcStop: 2019-10-24T16:00:00Z/2019-10-25T16:00:00Z

secondsSinceEpochStart/secondsSinceEpochStop: 1571932800/1572019200

See all this code run live at IdeOne.com. You can easily fork and experiment there.

By the way, if you are doing much work with a span-of-time tracking a pair of moments, add the ThreeTen-Extra library to your project to access the class Interval. This class represents a pair of Instant objects, along with many helpful methods such as abuts, contains, and so on.

ZonedDateTime start = LocalDate.of( 2019, Month.OCTOBER , 25 ).atStartOfDay( ZoneOffset.UTC ) ;
Interval dayInUtc = Interval.of( 
    start.toInstant() ,
    start.plusDays( 1 ).toInstant() 
) ;
String epochCounts = dayInUtc.getStart().getEpochSecond() + "/" + dayInUtc.getEnd().getEpochSecond() ;

…and in a time zone:

ZonedDateTime start = LocalDate.of( 2019, Month.OCTOBER , 25 ).atStartOfDay( ZoneId.of( "Asia/Kuala_Lumpur" ) ) ;
Interval dayInKualaLumpur = Interval.of( 
    start.toInstant() ,
    start.plusDays( 1 ).toInstant() 
) ;
String epochCounts = dayInKualaLumpur.getStart().getEpochSecond() + "/" + dayInKualaLumpur.getEnd().getEpochSecond() ;

Upvotes: 2

Related Questions