0

I work at a company where part of the work for a day is done in the early hours of the next day (i.e. shipping orders). Now for several processes (mainly reporting), we want to let the 'working day' end at 04:00 the next morning so we get more consistent reporting values per day.

We want this to always be at 04:00 the next morning and since we are affected by daylight saving times in our area (Europe - Netherlands) we effectively want a 4 hour shifted variant of our normal timezone 'Europe/Amsterdam' (in our case).

To make this as easy to use for all applications in our company I would like to create a small library that simply contains the code to provide my coworkers to get a modified instance of TimeZone that does this. That way all normal time/date manipulation methods can be used in conjunction with this special time zone.

I did a deep dive into the standard Java 8 code/Javadoc related to the TimeZone/ZoneInfo instances and at this moment I do not understand what the correct field is to change in the returned TimeZone/ZoneInfo instance.

At this point, my best guess is setting the RawOffset to 4 hours, but I'm not sure.

What is the correct way to achieve my goal?


Update:

I had a look at the suggested LocalTime and as I expected: It needs a timezone definition as being what it should use as "Local" when converting an existing timestamp (usually epoch milliseconds) into the "Local" timezone.

Looking at all these classes seems like I'll be using the LocalDate more often than the LocalTime.

Effectively the code I expect to have is something like this:

long epoch =  1525033875230L; // Obtained from some dataset
LocalDate localDate = LocalDateTime
  .ofInstant(Instant.ofEpochMilli(epoch), 
             ZoneId.of("Europe/Amsterdam"))
  .toLocalDate();

Where I expect that I need to change that Zone into the 'right one'.

Niels Basjes
  • 10,424
  • 9
  • 50
  • 66
  • During daylight saving, you still want the working day to end at 4:00 _local time_ right? Or do you want it to end at 5 during daylight saving? If it's the former case, use `LocalTime`. – Sweeper Apr 29 '18 at 09:59
  • We always want the LocalTime so in our code we will have to use that with the custom timezone I'm looking for. – Niels Basjes Apr 29 '18 at 10:05
  • 1
    What I mean is that you might not need a `TimeZoneInfo`. No matter what time of the year, the working day ends when the clock shows 4:00, right? That's a use case of `java.time.LocalTime`. – Sweeper Apr 29 '18 at 10:07
  • What is the correct way to do something incorrect? Hard to tell. :-) Have you considered whether using `LocalDateTime` throughout would work for you? It doesn’t have a time zone. Then of course it also doesn’t give you what a time zone gives. – Ole V.V. Apr 29 '18 at 15:49
  • 1
    [Here is a very long answer explaining how to create your own `ZoneId` object](https://stackoverflow.com/a/44419074/5772882). – Ole V.V. Apr 29 '18 at 15:59
  • @OleV.V. We use just about everywhere the epoch milliseconds to store when something happened and then convert it into the right representation when needed. In this case I think we really need a 'new' Zone. – Niels Basjes Apr 29 '18 at 21:09

1 Answers1

2

If I have got that correctly, what you really need is a way to convert a milliseconds value since the epoch to a date in a way where days don’t change a 00:00 but not until 04:00.

static ZoneId zone = ZoneId.of("Europe/Amsterdam");
static LocalTime lastShiftEnds = LocalTime.of(4, 0);

public static LocalDate epochMilliToDate(long epoch) {
    ZonedDateTime dateTime = Instant.ofEpochMilli(epoch)
            .atZone(zone);
    if (dateTime.toLocalTime().isAfter(lastShiftEnds)) { // normal date-time
        return dateTime.toLocalDate();
    } else { // belonging to previous day’s night shift
        return dateTime.toLocalDate().minusDays(1);
    }
}

Use for example like this:

    long epoch = 1_525_050_875_230L;
    System.out.println(Instant.ofEpochMilli(epoch));
    LocalDate date = epochMilliToDate(epoch);
    System.out.println(date);

Output is:

2018-04-30T01:14:35.230Z
2018-04-29

From printing the Instant you can see that the time is after midnight (really 03:14:35.230 in Amsterdam time zone). And the method has correctly deemed that this time belongs to April 29 rather than April 30.

Perhaps I am missing something? On the other hand, if that were me I’d go quite a long way to avoid inventing a time zone that doesn’t exist in real life. Such a time zone would be bound to confuse your coworkers.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161