Finding which timezone names are at 8am - java

I have a user table in MySQL with a time zone column in Europe/Paris format. My goal is to find user for whom it's currently 8am from my Java app.
Just using Europe/Paris won't work because Europe/Brussels and Europe/Amsterdam have the same time zone and DST. So I would like to find all possible names for a specific time.
I also can't just use the GMT+1 offset as the daylight saving times will shift it during the summer and it will not switch for everyone on the same date.
I checked the TimeZone classes and couldn't find this.

In general:
Get the current time in UTC.
For each time zone, convert to that zone's local time.
If the local time is the time you're looking for, then you have a match.
Query for all users with matching time zones.
A few points:
You could do this either in MySQL, or in Java. You didn't really say which you were looking for.
You could optimize by limiting the time zones to test. You'd have to ahead-of-time determine the standard and daylight offsets of each zone, then use this as a filter.
When you check for "is it 8AM?" - you probably don't want to do an exact equality check, because it will only be 8:00:00.000 for one millisecond. Instead you probably want to test against a range of values, such as time >= 8:00 AND time < 9:00

Related

Should I use Instant or DateTime or LocalDateTime in Java entities?

In my Java (with Spring Boot and Spring Data JPA) applications, I generally use Instant. On the other hand, I would like to use the most proper data type for time values.
Could you please clarify me about these issues? What data type should I prefer for keeping date and time when:
1. To keep time precisely as timestamp (I am not sure if Instant is the best option)?
2. For normal cases when I just need date and time (as far as I know, the old library was obsolete, but not sure which library should I use).
I also consider the TimeZone, but not sure if using LocalDateTime with UTC solves my problem.
Any help would be appreciated.
Let's assume we need to cover the full span of date and time concerns. If there is a certain concern you don't have, that either collapses various types into 'well then they are interchangible' or simply means you don't need to use a certain part of the API. The point is, you need to understand what these types represent, and once you know that, you know which one to apply. Because even if various different java.time types all technically do what you want, code is more flexible and a lot simpler to read if the types you use represent the things you want them to. For the same reason String[] student = new String[] {"Joe McPringle", "56"}; is perhaps mechanically a way to represent a student's name and age, but things are just a lot simpler if you write a class Student { String name; int age; } and use that instead.
Local alarm clock
Imagine you want to wake up at 07:00 in the morning. Not because you have an appointment, you just like to be a fairly early riser.
So you set your alarm for 07:00 in the morning, go to sleep, and your alarm promptly goes off at 7. So far, so good. However, you then hop in a plane and fly from Amsterdam to New York. (it is 6 hours earlier in new york). You then go to sleep again. Should the alarm go off at 01:00 at night, or at 07:00 in the morning?
Both answers are correct. The question is, how do you 'store' that alarm, and to answer that question, you need to figure out what the alarm is attempting to represent.
If the intent is '07:00, whereever I might be at the time the alarm is supposed to go off', the correct data storage mechanism is java.time.LocalDateTime, which stores time in human terms (years, months, days, hours, minutes, and seconds) and not in computery terms (we'll get there later), and does not include a time zone at all. If the alarm is supposed to go off every day, then you don't want that either, as LDT stores date and time, hence the name, you'd use LocalTime instead.
That's because you wanted to store the concept of 'the alarm should go off at 7 o'clock' and nothing more than that. You had no intention of saying: "The alarm should go off when people in Amsterdam would agree it is currently 07:00", nor did you have the intent of saying: "When the universe arrives at this exact moment in time, sound the alarm". You had the intent of saying: "When it is 07:00 where-ever you are now, sound the alarm", so store that, which is a LocalTime.
The same principle applies to LocalDate: It stores a year/month/day tuple with no notion of where.
This does draw some perhaps wonky conclusions: Given a LocalDateTime object, it is not possible to ask how long it'll take until that LDT arrives. It is also not possible for any given moment in time to be compared to an LDT, because these things are apples and oranges. The notion 'Feb 18th, 2023, 7 in the morning on the dot' isn't a singular time. After all, in New York that 'moment' occurs a full 6 hours earlier than it would in Amsterdam. You can only compare 2 LocalDateTimes.
Instead, you would have to first 'place' your LDT somewhere, by converting it to one of the other types (ZonedDateTime or even Instant) by asking the java.time API: Okay, I want this particular LDT in a certain time zone.
Hence, if you are writing your alarm app, you would have to take the stored alarm (a LocalTime object), convert it to an Instant (which is what the nature of 'what time is it now, i.e. System.currentTimeMillis()' works on), by saying: That LocalTime, on the current day in the current local timezone, as an instant, and THEN comparing those two results.
Human appointments
Imagine that, just before jetting off to New York, you made an appointment at your local (in Amsterdam) barber. Their agenda was kinda busy so the appointment was set for June 20th, 2025, at 11:00.
If you stay in New York for a few years, the correct time for your calendar to remind you that you have an appointment with your barber's in an hour is certainly not at 10:00 on june 20th 2025 in New York. You'd have missed the appointment by then. Instead, your phone should chirp at you that you have an hour left to get to your barber's (a bit tricky, from New York, sure) at 04:00 in the middle of the night.
It sure sounds like we can say that the barber's appointment is a specific instant in time. However, this is not correct. The EU has already adopted legislation, agreed upon by all member states, that all EU countries shall abolish daylight savings time. However, this law does not provide a deadline, and crucially, does not provide a time zone that each EU member state needs to pick. The Netherlands is therefore going to change time zones at some point. They will likely choose to stick either to permanent summer time (in which case they'd be at UTC+2 permanently, vs. their current situation where they are at UTC+2 in summer and UTC+1 in winter, with, notably, different dates when the switch happens vs. New York!), or stay on winter time, i.e. UTC+1 forever.
Let's say they choose to stick to winter time forever.
The day the gavel slams down in the dutch parliament building enshrining into law that the dutch will no longer advance the clocks in march is the day your appointment shifts by one hour. After all, your barber is not going to go into their appointment book and shift all appointments by an hour. No, your appointment will remain on June 20th, 2025, at 11:00. If you have a running clock ticking down the seconds until your barber appointment, when that gavel comes down it should jump by 3600 seconds.
This belies the point: That barber appointment truly is not a singular moment in time. It's a human/political agreement that your appointment is when Amsterdam universally agrees it is currently June 20th, 2025, 11:00 – and who knows when that moment will actually occur; it depends on political choices.
So, you cannot 'solve' this by storing an instant in time, and it shows how the concept 'instant in time' and 'year/month/day hour:minute:second in a certain timezone' are not quite interchangible.
The correct data type for this concept is a ZonedDateTime. This represents a date time in human terms: year/month/day hour:second:minute, and the timezone. It doesn't shortcut by storing a moment in time in epochmillis or some such. If the gavel comes down and your JDK updates its timezone definitions, asking "how many seconds until my appointment" will correctly shift by 3600 seconds, which is what you want.
Because this is for appointments and it doesn't make sense to store just the time of an appointment but not the date, there is no such thing as a ZonedDate or a ZonedTime. Unlike the first thing which comes in 3 flavours (LocalDateTime, LocalDate, and LocalTime), there's only ZonedDateTime.
The universe/log time
Imagine you are writing a computer system that logs that an event occurred.
That event, naturally, has a timestamp associated with it. Turns out that due to severe political upheaval, the laws of the land decide that retrospectively the country has been in a different timezone than what you thought when the event occurred. Applying the same logic as the barber's case (where the actual moment in time jumps by 3600 seconds when the gavel comes down) is incorrect. The timestamp represents a moment in time when a thing happened, not an appointment in a ledger. It should not jump by 3600.
Timezone really has no purpose here. The point of storing 'timestamp' for a log event is so you know when it happened, it doesn't matter where it happened (or if it does, that is fundamentally a separate notion).
The correct data type for this is java.time.Instant. An instant doesn't even know about time zones at all, and isn't a human concept. This is 'computery time' - stored as millis since an agreed upon epoch (midnight, UTC, 1970, new years), no timezone information is necessary or sane here. Naturally there is no time-only or date-only variant, this thing doesn't even really know what 'date' is - some fancypants human concept that computery time is not concerned with in the slightest.
Conversions
You can trivially go from a ZonedDateTime to an Instant. There's a no-args method that does it. But note:
Create a ZonedDateTime.
Store it someplace.
Convert it to an Instant, store that too.
Update your JDK and get new time zone info
Load the ZDT.
Convert it to an Instant a second time.
Compare the 2 ZDTs and the 2 instants.
Results in different results: The 2 instants would not be the same, but the ZDTs are the same. The ZDT represents the appointment line in the barber's book (which never changed - 2025 june 20th, 11:00), the instant represents the moment in time that you are supposed to show up which did change.
If you store your barber's appointment as a java.time.Instant object, you will be an hour late to your barber's appointment. That's why it's important to store things as what they are. A barber's appointment is a ZonedDateTime. storing it as anything else would be wrong.
Conversions are rarely truly simple. There is no one way to convert one thing to another - you need to think of what these things represent, what the conversion implies, and then follow suit.
Example: You are writing a logging system. The backend parts store log events into a database of some sort, and the frontend parts read this database and show the log events to an admin user for review. Because the admin user is a human being, they want to see it in terms they understand, say, the time and date according to UTC (it's a programmer, they tend to like that sort of thing).
The logging system's storage should be storing the Instant concept: Epoch millis, and without timezone because that is irrelevant.
The frontend should read these as Instant (it is always a bad idea to do silent conversions!) - then consider how to render this to the user, figure out that the user wants these as local-to-UTC, and thus you would then on the fly, for each event to be printed to screen, convert the Instant to a ZonedDateTime in the zone the user wants, and from there to a LocalDateTime which you then render (because the user probably does not want to see UTC on every line, their screen estate is limited).
It would be incorrect to store the timestamps as UTC ZonedDateTimes, and even more wrong to store them as LocalDateTimes derived by asking for the current LocalDT in UTC as the event happens and then storing that. Mechanically all these things would work but the data types are all wrong. And that will complicate matters. Imagine the user actually wants to see the log event in Europe/Amsterdam time.
A note about timezones
The world is more complicated than a handful of timezones. For example, almost all of mainland europe is currently 'CET' (Central European Time), but some think that refers to european winter time (UTC+1), some thing that refers to the current state in central europe: UTC+1 in winter, UTC+2 in summer. (There's also CEST, Central European Summer Time, which means UTC+2 and isn't ambiguous). When EU countries start applying the new law to get rid of daylight savings, its likely e.g. The Netherlands on the west edge of the CET zone picks a different time than Poland on the eastern edge. Hence, 'all of central europe' is far too broad. 3-letter acronyms also are by no means unique. Various countries use 'EST' to mean 'eastern standard time', it's not just the eastern USA for example.
Hence, the only proper way to represent timezone names is using strings like Europe/Amsterdam or Asia/Singapore. If you need to render these as 09:00 PST for residents of the west coast of the USA, that's a rendering issue, so, write a rendering method that turns America/Los_Angeles into PST, which is an issue of localization, and has nothing to do with time.
The Answer by rzwitserloot is correct and wise. In addition, here is a summary of the various types. For more info, see my Answer on a similar Question.
To keep time precisely as timestamp (I am not sure if Instant is the best option)?
If you want to track a moment, a specific point on the timeline:
InstantA moment as seen with an offset-from-UTC of zero hours-minutes-seconds. This class is the basic building-block of the java.time framework.
OffsetDateTimeA moment as seen with a particular offset, some number of hours-minutes-seconds ahead of, or behind, the temporal meridian of UTC.
ZonedDateTimeA moment as seen with a particular time zone. A time zone is a named history of the past, present, and future changes to the offset used by the people of a particular region, as decided by their politicians.
If you want to track just the date and time-of-day, without the context of an offset or time zone, use LocalDateTime. This class does not represent a moment, is not a point on the timeline.
For normal cases when I just need date and time
If you are absolutely sure that you want only a date with time-of-day, but do not need the context of an offset or time zone, use LocalDateTime.
using LocalDateTime with UTC
That is a contradiction, and makes no sense. A LocalDateTime class has no concept of UTC, nor any concept of offset-from-UTC or time zone.
Spring Data JPA
The JDBC 4.2+ specification maps SQL standard data types to Java classes.
TIMESTAMP WITH TIME ZONE columns map to OffsetDateTime in Java.
TIMESTAMP WITHOUT TIME ZONE columns map to LocalDateTime in Java.
DATE columns map to LocalDate.
TIME WITHOUT TIME ZONE columns map to LocalTime.
The SQL standard also mentions TIME WITH TIME ZONE, but this type is meaningless (just think about it!). The SQL committee has never explained what they had in mind, as far as I know. If you must use this type, Java defines the ZoneOffset class to match.
Note that JDBC does not map any SQL types to Instant nor ZonedDateTime. You can easily convert to/from the mapped type OffsetDateTime.
Instant instant = myOffsetDateTime.toInstant() ;
OffsetDateTime myOffsetDateTime = instant.atOffset( ZoneOffset.UTC ) ;
… and:
ZonedDateTime zdt = myOffsetDateTime.atZoneSameInstant( myZoneId ) ;
OffsetDateTime odt = zdt.toOffsetDateTime() ; // The offset in use at that moment in that zone.
OffsetDateTime odt = zdt.toInstant().atOffset( ZoneOffset.UTC ) ; // Offset of zero hours-minutes-seconds from UTC.
I also consider the TimeZone
The TimeZone class is part of the terrible legacy date-time classes that were years ago supplanted by the modern java.time classes. Replaced by ZoneId and ZoneOffset.
You should take a look at the Java Date and Time API introduced with Java 8. Each class like Instant, LocalDateTime, ZonedDateTime etc. has a documentation as JavaDoc. If you have problems understanding the documentation, please provide a more specific question.

Using localDate with UTC

I'm encountering a problem using LocalDate in UTC. My server uses UTC, and my database uses UTC. I used LocalDate to store a billingDate for a subscription based application.
What happens is that we bill at midnight UTC (when doing comparisions like billingDate <= LocalDate.now()). We actually mean to bill sometime after midnight PST.
I really felt like using LocalDate was appropriate here, because we just want to bill at some point during that day. However, it doesn't seem practical when doing comparisons either directly in the code or in the database (billing_date <= CURRENT_DATE()). Did I make a mistake, should this be a ZonedDateTime in PST? Or should we be converting to ZonedDateTime for comparisons? It feels error prone, we need to remember to convert any time we do a comparision, but perhaps this is the correct solution?
Does anyone have experience with this situation and found a nice solution?
I've taken a look at this question, but it doesn't answer my question: Spring REST LocalDate UTC differs of one day
I suggest that this is just a matter of passing the desired time zone to LocalDate.now(ZoneId).
Use LocalDate.now(ZoneId.of("Asia/Manila")) for Philippine Standard Time. At the moment it yeilds 2019-07-09.
Use LocalDate.now(ZoneId.of("Pacific/Pitcairn")) for Pitcairn Standard Time. It just gave 2019-07-08.
I am assuming that you didn’t mean Pacific Standard Time since no time zone uses Pacific Standard Time as we speak (those that do in winter, are on Pacific Daylight Time now). In any case, mind you that three letter time zone abbreviations are often ambiguous.
The java.time classes that have a now method generally have three overloaded variants of it:
One that takes a ZoneId arguments that I recommend for general use.
One that takes a Clock argument that is great for testability. A Clock includes a time zone, so this one too gets you the current date and/or time in that specified time zone.
One that doesn’t take any arguments and uses the JVM’s default time zone. I recommend that you never use it. It’s nice for the reader to know that you have considered time zone and chosen which one you want. And the default time zone can be changed at any time by any program running in the same JVM, so is not stable enough to rely on for real work.
I feel like you should be using Instants.
I really felt like using LocalDate was appropriate here, because we just want to bill at some point during that day.
Well, no. You do care about the time you bill, because your database cares about the time. It stores the billing time as 00:00 UTC. Since that is an instant in time, I think Instant would be the most suitable choice here. You could use a ZonedDateTime as well, but considering that you are probably getting a java.sql.Date from your database, which has a toInstant method already, using Instants is more convenient.
You can get an instant from a year, month, day like this:
LocalDate ld = LocalDate.of(2019, 7, 8);
Instant i = ld.atStartOfDay(ZoneId.of("America/Los_Angeles")).toInstant();
America/Los_Angeles is PST.

How to gather timezone of operating system from Oracle database in string format? (Migrate/convert date to ts with tz)

I want to update a database table which uses date type to timestamp with timezone type in such a way that the old dates get correct timezone information.
The plain cast is not good for me because if the time zone is for example UTC+2 hours (UTC+1 + 1 hour for daylightsaving) and I try to cast dates to timestamp with timezone, all the dates in the database table got the same +2 hour as timezone offset, regardless if it's a summer time or winter time date.
I already can write an SQL query which can determine about a date if it is in daylightsaving time or not, IF I know the current time zone in string format, e.g. 'Europe/Berlin'. The problem is that dbtimezone and sessiontimezone can be stored in other formats, too (+02:00, CET, etc). I cannot easily set the current sessiontimezone in a static way, because there are customers in several places on the globe with their own databases, but using a common update script.
Express method for timestamp can not help neither, because it cannot map the offset to named time zones.
I've seen a solution which uses java stored procedure to get the OS’s timezone instead of Oracles timezone. Unfortunately we use Oracle 12c, which contains an older JRE (I think it's 1.6 version). So, although Java 1.8 handles the timezones and daylight saving well (it uses updated tzmapping table), it does not work for me. I tryed it and if I run a test from Netbeans, then it gives me back the right time zone ID (in Europe/Berlin format), but even if it is accepted by Oracle SQL Developer, SQLPlus (which we use for running update scrips), it displays only +02:00.
I've tryied to use JodaTime (recompiled onto Java 1.6 in order to be accepted by SQL*Plus). The latest JodaTimes uses its own mapping table in theory. I read here on StackOverflow that if it cannot gather the time zone from user.timezone variable, then it turns to java.util, which is not good, as I mentioned. And if it does not succeed, then uses UTC. But it's not clear to me why it cannot get timezone from user.timezone systemm variable. Is it a permission problem maybe?
Or how could I possibly solve this issue? Thank you!
If the data is already in an Oracle SQL table, and you must convert to a timestamp with time zone (for example, in a new column you created in the same table), you do not need to go explicitly to the OS, or to use Java or any other thing, other than the Oracle database itself.
It is not clear from your question if you must assume the "date" was meant to be in the server time zone (you mention "the database" which normally means the server) or the client time zone (you mention "session" which means the client). Either way:
update <your_table>
set <timestamp_with_time_zone_col> =
from_tz(cast<date_col> as timestamp, dbtimezone)
;
or use sessiontimezone as the second argument, if that's what you need.
This assumes that the database (and/or the session) time zone is set up properly in the db, respectively in the client. If it isn't / they aren't, that needs to be fixed first. Oracle is perfectly capable of handling daytime savings time, if the parameters are set correctly in the first place. (And if they aren't, it's not clear why you would try to get your operation to be "more correct" than the database supports in the first place.)
Example: in the WITH clause below, I simulate a table with a column dt in data type date. Then I convert that to be a timestamp with time zone, in my session's (client) time zone.
with
my_table ( dt ) as (
select to_date('2018-06-20 14:30:00', 'yyyy-mm-dd hh24:mi:ss') from dual
)
select dt,
from_tz(cast(dt as timestamp), sessiontimezone) as ts_with_tz
from my_table
;
DT TS_WITH_TZ
------------------- -------------------------------------------------
2018-06-20 14:30:00 2018-06-20 14:30:00.000000000 AMERICA/LOS_ANGELES
The question in your title
How to gather timezone of operating system from Oracle database in string format?
is easy to answer. Run this statement:
SELECT TO_CHAR(SYSTIMESTAMP, 'tzr') FROM dual;
But I assume you have a different problem, however I don't fully understand it.
When you have a column of TIMESTAMP WITH TIME ZONE then the time zone information is available. Time zones like +02:00 do not have any daylight savings, it is always 2 hour ahead UTC, no matter if summer or winter. Timezones like Europe/Berlin or CET apply Daylight Saving Times.
If you have a time for example 2018-06-22 10:00:00+02:00 then you simply don't know whether this means Europe/Berlin with Daylight Saving Time on or Africa/Cairo which is always +02:00 hours ahead UTC - you have no possibility to retrieve such information!
If you have data in column of DATE (or TIMESTAMP) then you don't have any time zone information at all, thus you cannot convert such values to TIMESTAMP WITH TIME ZONE without further information.
Storing times in timezone of operating system is rather useless. Either store them in UTC or use data type TIMESTAMP WITH LOCAL TIME ZONE. Data in TIMESTAMP WITH LOCAL TIME ZONE are stored in DBTIMEZONE (which is recommended to be set as UTC but actually not relevant for you) and always and only shown in current user SESSIONTIMEZONE.

CST/CDT time zone change issue

We are storing time in like '22-NOV-17 05.33.51.937000000 PM' format with server default timezone CST. We have half an our time comparison in many places. So CST to CDT and CDT to CST are facing issues because on retrieval time for database we can not identify the time zone. So it is breaking our time comparison on CST to CDT and CDT to CST time changes.
We can not change our storing logic like store with timezone and store in UTC timezone because it will breaking our existing logic in many places.
So is there any way to identity date timezone like CST or CDT, stored in database with '22-NOV-17 05.33.51.937000000 PM' format.
We are storing time in like '22-NOV-17 05.33.51.937000000 PM' format
does not make sense with your comment
We are storing as a timestamp in database
In Oracle databases, a TIMESTAMP does not have a format - it is stored in the database as 11 bytes representing year (2 bytes), month, day, hours, minutes, seconds (1 byte each) and fractional seconds (4 bytes). It is only when whatever interface you are using (SQL/Plus, SQL Developer, Toad, Java, PHP, etc.) to talk to the database decides to show it to you, the user, that that interface will format it as a string (but the database will just keep it as bytes without any format).
Assuming you are using SQL/Plus or SQL Developer then you can find the default format using:
SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_TIMESTAMP_FORMAT';
And change the default format using:
ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFF9';
Or for TIMESTAMP WITH TIME ZONE
ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SSXFF9 TZR';
So is there any way to identity date timezone like CST or CDT, stored in database with '22-NOV-17 05.33.51.937000000 PM' format.
No, without any other meta-data that could identify the source of the timestamp and indicate which location it came from (i.e. is there another column that links to the user who entered the data that could be mapped to a physical location and so a time zone) then it is impossible to determine which time zone it is from.
You will either need to:
change your database column to TIMESTAMP WITH TIME ZONE and store the time zone; or
convert all the values to the same time zone when you are storing them.
I am assuming by CST and CDT you mean North American Central Standard Time and Central Daylight Time such as observed in Rainy River, Chicago and Mexico (the city) among other places. More on this ambiguity later.
For 99.977 % of all times it is fairly easy to know whether they are standard time or daylight saving time. Only times from the two hours around the transition from DST to standard time are ambiguous, and as said in the comments, there is no way to know from the time stamp which is the right way to resolve this ambiguity.
java.time
This answer will take you as far into the future as possible without taking you away from Java 7. You can still use java.time, the modern Java date and time API also known as JSR-310. It has been backported to Java 6 and 7 in the ThreeTen Backport, so it’s a matter of getting this and adding it to your project (just until one day you upgrade to Java 8 or later).
I am taking your word for your date-time string format. What we can do with it:
DateTimeFormatter storedFormatter = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendPattern("d-MMM-uu hh.mm.ss.SSSSSSSSS a")
.toFormatter(Locale.US);
ZoneId zone = ZoneId.of("America/Mexico_City");
String storedTime = "22-NOV-17 05.33.51.937000000 PM";
LocalDateTime dateTime = LocalDateTime.parse(storedTime, storedFormatter);
// First shot -- will usually be correct
ZonedDateTime firstShot = ZonedDateTime.of(dateTime, zone);
System.out.println(firstShot);
This prints:
2017-11-22T17:33:51.937-06:00[America/Mexico_City]
You can see that it picked an offset of -06:00, which means that the time is in standard time (CDT is -05:00).
Since your month abbreviation is in all uppercase, I needed to tell the formatter to parse case insensitively. If America/Mexico_City time zone is not appropriate for you, pick a better one, for example America/Rainy_River or America/Chicago.
Ambiguous times in fall
I once had to parse a log file containing date-times without indication of standard time and summer time (DST). Since we assumed time would always move forward, we failed at the transition to standard time, and one hour of the log file was lost. In this case we might have solved it using the information that times were in summer time until the leap backward by an hour, from there they were in standard time. You may want to think about whether something similar will be possible for you.
Other options include just taking DST time every time — this is what the above code will do — or taking an average and living with the error thus introduced.
We can at least detect the ambiguous times:
ZoneOffset standardOffset = ZoneOffset.ofHours(-6);
ZoneOffset dstOffset = ZoneOffset.ofHours(-5);
// check if in fall overlap
ZonedDateTime standardDateTime
= ZonedDateTime.ofLocal(dateTime, zone, standardOffset);
ZonedDateTime dstDateTime
= ZonedDateTime.ofLocal(dateTime, zone, dstOffset);
if (! standardDateTime.equals(dstDateTime)) {
System.out.println("Ambiguous, this could be in CST or CDT: " + dateTime);
}
Now if the string was 29-OCT-17 01.30.00.000000000 AM, I get the message
Ambiguous, this could be in CST or CDT: 2017-10-29T01:30
ZonedDateTime.ofLocal() will use the provided offset for resolving the ambiguity if it is a valid offset for the date-time and zone.
Non-existing times in the spring
Similarly we can detect if your date-time falls in the gap where the clock is moved forward in the transition to DST:
// Check if in spring gap
if (! firstShot.toLocalDateTime().equals(dateTime)) {
System.out.println("Not a valid date-time, in spring gap: " + dateTime);
}
This can give a message like
Not a valid date-time, in spring gap: 2018-04-01T02:01
I suggest you can safely reject such values. They cannot be correct.
Avoid the three letter time zone abbreviations
CST may refer to Central Standard Time (in North and Central America), Australian Central Standard Time, Cuba Standard Time and China Standard Time. CDT may mean Central Daylight Time or Cuba Daylight Time. The three and four letter abbreviations are not standardized and are very often ambiguous. Prefer time zone IDs in the region/city format, for example America/Winnipeg.

How to determine if a timestamp is within working hours?

Given a any unix timestamp (i.e. 1306396801) which translates to 26.05.2011 08:00:01, how can I determine if this is within a given timeframe (i.e. 08:00:00 and 16:00:00)?
This needs to work for any day. I just want to know if this timestamp is within the given time-interval, on any future (or past) day, the date is unimportant. I don't care if it is on the 25th or 26th, as long as it is between 08:00 and 16:00.
I am on the lookout for a java solution, but any pseudo code that works will be ok, I'll just convert it.
My attempts so far has been converting it to a java Calendar, and reading out the hour/min/sec values and comparing those, but that just opened up a big can of worms. If the time interval I want it between is 16.30, I can't just check for tsHour > frameStartHour && tsMin > frameStartMin as this will discard any timestamps that got a minute part > 30.
Thank you for looking at this :)
To clarify.
I am only using and referring to UTC time, my timestamp is in UTC, and the range I want it within is in UTC.
I think I understand what you want. You want to test for any day, if it's between 8am and 4pm UTC. Take the timestamp mod 24*3600. This will give you the number of seconds elapsed in the day. Then you just compare that it's between 8*3600 and 16*3600. If you need to deal with timezones, things get more complicated.
Given your timestamp (in seconds) and the desired time zone, Jodatime gives you the hour which leads you to a simple integer range check.
new org.joda.time.DateTime(timestamp*1000L, zone).getHourOfDay()
With java.util.* its more difficult.
If I understood you correctly, you only need to normalize your dates to some common value. Create three instances of Calendar - one with your time, but day, month, and year set to zero, and two with start and end of your timeframe, other fields also zeroed. Then you can use Calendar.after() and Calendar.before() to see if the date is within the range.
Your unix timestamp is an absolute time. Your time frame is relative. You need some kind of time zone information in order to solve this problem. I just answered some of this for PostgreSQL a few minutes ago. Hopefully that article is of use.
Convert the beginning of your range to a unix timestamp, and the end of your range to a unix tmestamp, then it's a simple integer check.

Categories