I am defining a Joda interval as follows:
final DateTimeZone fromDtz = DateTimeZone.forID("Europe/Paris");
final DateTime fromDt = DateTime.parse("2013-08-08T01:02:03+0200").withZone(fromDtz);
final DateTimeZone toDtz = DateTimeZone.forID("Europe/London");
final DateTime toDt = DateTime.parse("2013-08-08T01:02:05+0100").withZone(toDtz);
final Interval interval = new Interval(fromDt, toDt);
However it appears that I lose the information on the timezone for the end of the interval. If I do a simple toString() on the interval I receive:
2013-08-08T01:02:03.000+02:00/2013-08-08T02:02:05.000+02:00
which is missing some of the information I'm trying to retain (the specific timezone of the datetime at the end of the interval).
I've wandered through the documentation and source code and it appears that Interval only contains a single chronology. Is there a way to tell Joda to keep both timezones without manually carting around two separate DateTimes?
Fundamentally an interval is the time between two instants - and instants don't have chronologies, time zones etc. They're just points on a universal time line - a number of milliseconds since an epoch. The fact that ReadableInterval exposes getChronology at all is a design flaw, IMO - but there really is only one such chronology. If you're trying to keep more information than that, I believe you'll need to use your own type.
It may be as simple as a start/end pair and a toInterval() method for places where you really want to use the Joda Time Interval methods, but I don't think there's anything built into Joda Time to do what you want.
try using withZoneRetainFields()
Related
I have two timestamp values. like
Timestamp date1;
Timestamp date2;
Now I want to find no. of days between these two timeStamps like in java
int no_of_days = difference(date2 - date1)
the above codes are just for clarification of the question. just ignore the coding mistakes.
You can use Duration for this (it works for java 8) :
Duration between = Duration.between(date1.toInstant(), date2.toInstant());
int no_of_days = between.get(ChronoUnit.DAYS);
If you are using Java8, it will be much easier. Here's a one way of doing it.
Duration.between(date1.toLocalDateTime(), date2.toLocalDateTime()).toDays();
Other answers given here so far only handle a day unit as fixed amount of 24 hours by using the class java.time.Duration. If you consider your timestamps in the context of daylight saving switching time zones then this is probably not what you want.
During the change from winter to summer time, a calendar day can last only 23 hours (or even 23:30 in some rare cases). And in autumn when switching back to winter time, the calendar days can be more than 24 hours long. So you also need a time zone to handle this situation in order to calculate durations in the correct way.
Suggested solution if your timestamps have been stored in the database coming from instants:
ZonedDateTime zdt1 = date1.toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime zdt2 = date2.toInstant().atZone(ZoneId.systemDefault());
long days = java.time.temporal.ChronoUnit.DAYS.between(zdt1, zdt2);
Of course, you are free to specify any other zone than the system time zone. The result can vary depending on the chosen zone.
Suggested solution if your timestamps have been stored coming from LocalDateTime without any zone context:
LocalDateTime ldt1 = date1.toLocalDateTime();
LocalDateTime ldt2 = date2.toLocalDateTime();
long days = java.time.temporal.ChronoUnit.DAYS.between(ldt1, ldt2);
Here I still prefer the enum ChronoUnit.DAYS because the type java.time.Duration internally stores seconds and nanoseconds only and is hence rather designed for machine-like timestamps. And another remark: The second solution implicitly uses your system time zone for the conversion from java.sql.Timestamp to LocalDateTime. This is only correct if you also have stored your timestamps that way.
By the way, with a JDBC-4.2-compliant driver, you could also retrieve your java.time-type directly, see also a related post here on SO.
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.
Before Java-8 I got accustomed to always keep anything date/time related as milliseconds since Epoch and only ever deal with human readable dates/times on the way out, i.e. in a UI or a log file, or when parsing user generated input.
I think this is still safe with Java-8, and now I am looking for the most concise way to get a formatted date out of a milliseconds time stamp. I tried
df = Dateformatter.ofPattern("...pattern...");
df.format(Instant.ofEpochMilli(timestamp))
but it bombs out with Unsupported field: YearOfEra in Instant.getLong(...) which I half understand. Now what to use instead of Instant?
LocalDateTime.ofEpoch(Instant, ZoneId) seems wrong, since I don't care to have local time. I just want to see the local time zone when applying the formatter. Internally it should be just the Instant.
The same goes for ZonedDateTime.ofInstant(Instant, ZoneId), I thought to apply the ZoneId only when formatting. But I notice that the DateTimeFormatter does not itself deal anymore with time zones, it seems, so I reckon I need to use one of the above.
Which one is preferred and why? Or should I use yet another way to format an epoch-millis time stamp as a date/time with time zone?
An Instant does not contain any information about the time-zone, and unlike in other places, the default time-zone is not automatically used. As such, the formatter cannot figure out what the year is, hence the error message.
Thus, to format the instant, you must add the time-zone. This can be directly added to the formatter using withZone(ZoneId) - there is no need to manually convert to ZonedDateTime *:
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
df.format(Instant.ofEpochMilli(timestamp))
* regrettably, in early Java 8 versions, the DateTimeformatter.withZone(ZoneId) method did not work, however this has now been fixed, so if the code above doesn't work, upgrade to the latest Java 8 patch release.
Edit: Just to add that Instant is the right class to use when you want to store an instant in time without any other context.
The error you have when formatting an Instant using a formatter built with a year or other fields is expected; an Instant does not know which year or month or day it is, it only knows how much milliseconds have elapsed since the Epoch. For the same instant, it could be 2 different days on 2 different places of the Earth.
So you need to add a time zone information if you want to print the day. With an Instant, you can call atZone(zone) to combine it with a ZoneId in order to form a ZonedDateTime. This is very much like an instant, only that it has a time zone information. If you want to use the system time zone (the one of the running VM), you can get it with ZoneId.systemDefault().
To print it, you can use the two built-in formatter ISO_OFFSET_DATE_TIME or ISO_ZONED_DATE_TIME. The difference between the two is that the zoned date time formatter will add the zone id to the output.
Instant instant = Instant.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.println(formatter.format(instant.atZone(ZoneId.systemDefault())));
System.out.println(formatter.format(instant.atZone(ZoneId.of("America/Los_Angeles"))));
when run on my machine, which has a system time zone of "Europe/Paris", you'll get:
2016-07-31T18:58:54.108+02:00
2016-07-31T09:58:54.108-07:00
You can of course build your own formatter if those one do not suit you, using ofPattern or the builder DateTimeFormatterBuilder.
I agree that this is somewhat confusing, especially when compared with it's predecessor Joda DateTime.
The most confusing thing is that the documentation for LocalDateTime says that it is "A date-time without a time-zone", and yet LocalDateTime.ofInstant method takes both an instant and a timezone as parameters.
That said, I think that you can achieve what you want by using Instant and LocalDateTime.ofInstant by using the UTC timezone.
public LocalDateTime millisToDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z");
}
I have a requirement of getting UTC time , hence in many places iam using below code for calcualting utc time.
System.currentTimeMillis() ;
Iam in IST - (GMT+5:30) , System.currentTimeMillis() - should display UTC time (IST-5:30) , instead it is taking current time (GMT+5:30).
I donot want to use the Apache of joda date and time api. i want to use the Java api itslef. Help me in resolve my issue.
System.currentTimeMillis() just returns a long - that's not in any sort of date format.
If you're actually using:
Date date = new Date(System.currentTimeMillis());
System.out.println(date);
then you're just seeing the result of Date.toString(), which always uses the system default time zone.
Use DateFormat (e.g. SimpleDateFormat) to specify the calendar system (typically Gregorian), time zone and format you want to use. For example:
Date date = ...;
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",
Locale.US);
format.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String result = format.format(date);
As an aside, I'd strongly recommend abstracting the idea of "getting the current time" into an interface which you implement in one case using System.currentTimeMillis() (or equivalently, just new Date()) but implement for testing purposes with a value you can set and update at will. Then inject this "clock" interface into anything which needs to access the current date/time. It makes it much easier to test time-based components.
(I'd also strongly recommend using Joda Time or the java.time package from Java 8 if you possibly can. I know you've said you don't want to, but I suspect that's because you haven't spent as much time swearing at java.util.Date and java.util.Calendar as some of us. Both of those alternatives will lead to much cleaner code which is much easier to read and reason about. If you're trying to avoid a one-time hit of getting Joda Time into your build process, weigh that against the amount of time you're likely to spend maintaining your code. Or just update to Java 8... Java 7 will be out of free-update support soon anyway...)
I have two strings from an android application in ISO 8601 format that I am trying to find the amount of minutes in between the two times. I was pointed to Joda Time which has been immensely helpful. However I have discovered now that one String is in UTC time and the other is my local time.
For example
"2012-05-11T02:34:18+00:00" is UTC and
"2012-05-10T21:44:09-05:00" is my local time
I have the following block of code which finds the number of minutes between the two times. My question is how can I go about to change the UTC time to my local time in order to get an accurate minutes in between
DateTime start = new DateTime(currentTime);
DateTime end = new DateTime(laterTime);
int min = Minutes.minutesBetween(start,end).getMinutes();
How do I go about to change the UTC time to my local time in order to get an accurate minutes in between?
My understanding is that you don't need to.
A DateTime instance represents a point on the time line, together with a timezone which controls how the time-point is mapped to a time frame (e.g. when you call the getters). When you take a time difference between a pair of DateTime instance, you get a measure representing the duration between two points on the timeline. This is independent of the timezones.
In other words, assuming that the two DateTime instances were created properly, your code should work as-is.