I'm looking to convert a Joda LocalDate to unix epoch time (long) in Java.
I've looked in to the LocalDate documentation and there doesn't appear to be anything on getting this value.
Link
I'm new to Joda and have been searching around and haven't found a right way of doing this yet. I know this has to be easy but I haven't figured it out. Any help would be appreciated.
In a general case it's not as simple as it seems - Unix time defines a continuous timeline starting at 1970-01-01 00:00 UTC. LocalDate is - as the name suggests - local to a certain place in the world. The beginning and end of the day 2015-01-01 is at a different point in time in Sydney than in Berlin. Also, Unix time involves time whereas LocalDate... not ;) So - if it indeed makes sense to convert a Local Date to a UTC timestamp there are two questions you must answer for yourself:
in which time zone do you want to interpret the LocalDate?
what should be the time part after the conversion?
Assuming it does make sense to do it and you can answer the questions, you can implement it using
LocalDate#toDateTime(LocalTime time, DateTimeZone zone)#getMillis()
or - if you want the start of the day
LocalDate#toDateTimeAtStartOfDay(DateTimeZone zone)#getMillis()
Related
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.
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'.
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.
Does anyone know why this method is behaving this way? 2013 is not a leap year, so I would expect that if I have a DateTime object like:
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dt = formatter.parseDateTime("2013-12-31 23:59:52");
That
dt.getDayOfYear()
would give me 365 but it's giving me 366. Can anyone see what the problem is?
I am also getting 366 if I do
dt.toString("DDD");
I would appreciate any input anyone might have.
Let me try an answer based on what I read from the docs and the code.
I assume your time stamp is indeed what you think it is, namely that last minute of 2013 UTC.
You create a DateTime object with the stamp in the default timezone. So if your local time zone is +01:00, this is 2013-14-01 00:59 +01:00.
Now you use withZoneRetainFields(UTC). From the docs I understand that this changes the milliseconds such that they actually reflect 2014-01-01 00:59 UTC, Basically this requires to add 3600*1000 millis to the time stamp, while changing the time zone entry in the object to UTC.
When you then ask for the day of the year, what actually happens internally is
.dayOfYear().get(getMillis())
My hunch is that dayOfYear is still based on 2013 and from this baseline you get day 366.
(I am not totally convinced myself of this answer I must admit and I wonder if there might be simply a bug lurking in Joda.)
Anyway: if you have UTC timestamps, I might suggest to just use new DateTime(stamp, UTC) where UTC a DateTimeZone object. Thereby you avoid the mind-bending double zone shifting.
EDIT: Further, if your stamp from the DB is genuinely UTC, by usingwithZoneRetainFields you change that stamp to denote another point in time, which has a good chance of being the wrong way to do whatever you are actually trying to do. In the confusing area of date/time handling, the time stamp in millis is the one easy to understand item. If it is not just for display purposes, I would never touch it.
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.
I have to prepare some app that will graph the use of resources over time, but there is one day on the year that has 25 hours (the day with 23 hours is not a big problem).
How can I represent that with a Date? What would be the best way of doing it?
I would like to use Date class, (as it works, is Comparable and so on) as a key, but I'm not sure if this would work... Any ideas?
The Date class itself simply represents an instant in time, from the UTC Unix epoch. It has no concept of time zones, calendars etc.
It's hard to know what exactly you're trying to represent, but in general Joda Time is a much better date/time API than the types in java.util.*.
My main advice on thinking about time-related issues is to be really, really clear about what concept each value is meant to be representing. If you're interested in a local date (a date within a particular calendar, with no reference to a particular time zone), then Joda Time's LocalDate class is probably what you're after. If you need to associate time zone information, then DateTime is probably your best bet - although that does represent an instant within a particular calendar and time zone, rather than a whole day.
It important not to confuse how time is represented and how it is displayed.
In its representation, you have only the number of milli-seconds since 1/1/1970. When you do calculations on this you are just comparing this long value.
When you display this time/date, depending on your timezone, you can have a period of 25 hours or 23 hours with the same day.