How to get milliseconds from LocalDateTime in Java 8 - java

I am wondering if there is a way to get current milliseconds since 1-1-1970 (epoch) using the new LocalDate, LocalTime or LocalDateTime classes of Java 8.
The known way is below:
long currentMilliseconds = new Date().getTime();
or
long currentMilliseconds = System.currentTimeMillis();

I'm not entirely sure what you mean by "current milliseconds" but I'll assume it's the number of milliseconds since the "epoch," namely midnight, January 1, 1970 UTC.
If you want to find the number of milliseconds since the epoch right now, then use System.currentTimeMillis() as Anubian Noob has pointed out. If so, there's no reason to use any of the new java.time APIs to do this.
However, maybe you already have a LocalDateTime or similar object from somewhere and you want to convert it to milliseconds since the epoch. It's not possible to do that directly, since the LocalDateTime family of objects has no notion of what time zone they're in. Thus time zone information needs to be supplied to find the time relative to the epoch, which is in UTC.
Suppose you have a LocalDateTime like this:
LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);
You need to apply the time zone information, giving a ZonedDateTime. I'm in the same time zone as Los Angeles, so I'd do something like this:
ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));
Of course, this makes assumptions about the time zone. And there are edge cases that can occur, for example, if the local time happens to name a time near the Daylight Saving Time (Summer Time) transition. Let's set these aside, but you should be aware that these cases exist.
Anyway, if you can get a valid ZonedDateTime, you can convert this to the number of milliseconds since the epoch, like so:
long millis = zdt.toInstant().toEpochMilli();

What I do so I don't specify a time zone is,
System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());
gives
ldt 1424812121078
ctm 1424812121281
As you can see the numbers are the same except for a small execution time.
Just in case you don't like System.currentTimeMillis, use Instant.now().toEpochMilli()

Since Java 8 you can call java.time.Instant.toEpochMilli().
For example the call
final long currentTimeJava8 = Instant.now().toEpochMilli();
gives you the same results as
final long currentTimeJava1 = System.currentTimeMillis();

To avoid ZoneId you can do:
LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);
System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());
Getting 0 as value, that's right!

You can use java.sql.Timestamp also to get milliseconds.
LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);

To get the current time in milliseconds (since the epoch), use System.currentTimeMillis().

You can try this:
long diff = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();

Why didn't anyone mentioned the method LocalDateTime.toEpochSecond():
LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);
This seems way shorter that many suggested answers above...

For LocalDateTime I do it this way:
LocalDateTime.of(2021,3,18,7,17,24,341000000)
.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli()

I think this is more simpler:
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
Assert.assertEquals(System.currentTimeMillis(), zdt.toInstant().toEpochMilli());
get the millis like System.currentTimeMillis() (from UTC).

There are some methods available that no one has mentioned here. But I don't see a reason why they should not work.
In case of LocalDate, you can use the toEpochDay() method. It returns the number of days since 01/01/1970. That number then can be easily converted to milliseconds:
long dateInMillis = TimeUnit.DAYS.toMillis(myLocalDate.toEpochDays());
Documentation can be found here.
In case of LocalDateTime, you can use the toEpochSecond() method. It returns the number of seconds since 01/01/1970. That number then can be converted to milliseconds, too:
long dateTimeInMillis = TimeUnit.SECONDS.toMillis(myLocalDateTime.toEpochSeconds());
Documentation for that is here.

If you have a Java 8 Clock, then you can use clock.millis() (although it recommends you use clock.instant() to get a Java 8 Instant, as it's more accurate).
Why would you use a Java 8 clock? So in your DI framework you can create a Clock bean:
#Bean
public Clock getClock() {
return Clock.systemUTC();
}
and then in your tests you can easily Mock it:
#MockBean private Clock clock;
or you can have a different bean:
#Bean
public Clock getClock() {
return Clock.fixed(instant, zone);
}
which helps with tests that assert dates and times immeasurably.

Date and time as String to Long (millis):
String dateTimeString = "2020-12-12T14:34:18.000Z";
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDateTime localDateTime = LocalDateTime
.parse(dateTimeString, formatter);
Long dateTimeMillis = localDateTime
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();

default LocalDateTime getDateFromLong(long timestamp) {
try {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
} catch (DateTimeException tdException) {
// throw new
}
}
default Long getLongFromDateTime(LocalDateTime dateTime) {
return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}

Related

Joda LocalDateTime from LocalDate and string

I have:
a joda LocalDate, so it has no time information and just date
a string which contains time and zone information, like "14:20 CEST"
Either of them can be absent (Scala's Option).
How can I combine these two to get joda LocalDateTime, i.e. entity representing only date and time with no timezone?
To combine these 2 options, the natural way is to use flatMap method like this:
val onlyDateOption: Option[LocalDate] = ???
val timeAndZoneOption: Option[String] = ???
val result: Option[LocalDateTime] = onlyDateOption.flatMap { onlyDate =>
timeAndZoneOption.map { timeAndZone =>
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
}
Which can also be written with for-comprehension in more readible way:
val result: Option[LocalDateTime] = for {
onlyDate <- onlyDateOption
timeAndZone <- timeAndZoneOption
} yield {
// Some logic here to build the LocalDateTime from onlyDate and timeAndZone
}
Now, how to use Joda to build what you're expecting can probably be done in various different ways, one could be:
onlyDate
.toLocalDateTime(LocalTime.MIDNIGHT)
.withHourOfDay(...) // hour extracted from the string somehow
.withMinuteOfHour(...) // minute extracted from the string somehow
I'm not familiar with Joda API, there is probably another easier way
How to combine LocalDate and String using Joda-Time
You have already got an answer treating the use of Option in detail. Here I want to go into more detail with the combination of your LocalDate and your String into a LocalDateTime using Joda-Time. I understand that you are getting a Joda-Time LocalDate from legacy code and need to return a Joda-Time LocalDateTime to legacy code. I am assuming that you know the time zone the abbreviation of which is in the string. I think that you should validate that abbreviation since Central European Time uses the abbreviation CET during the standard time part of the year and CEST during summer time (DST). Excuse my Java code.
DateTimeUtils.setDefaultTimeZoneNames(createTimeZoneNamesMap());
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("H:mm z");
LocalDate date = new LocalDate(2021, 5, 22);
String timeAndZoneString = "14:20 CEST";
LocalTime time = LocalTime.parse(timeAndZoneString, timeFormatter);
DateTime dateTime = date.toDateTime(time, ZONE);
// Validate time zone abbreviation; take overlap at fall-back into account
String earlierCorrectTimeString = dateTime.withEarlierOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(earlierCorrectTimeString)) {
String laterCorrectTimeString = dateTime.withLaterOffsetAtOverlap()
.toString(timeFormatter);
if (! timeAndZoneString.equals(laterCorrectTimeString)) {
throw new IllegalStateException("Incorrect time zone abbreviation for date");
}
}
LocalDateTime ldt = dateTime.toLocalDateTime();
System.out.println(ldt);
Output:
2021-05-22T14:20:00.000
I have used these two auxiliary declaration:
private static final DateTimeZone ZONE = DateTimeZone.forID("Europe/Paris");
private static Map<String, DateTimeZone> createTimeZoneNamesMap() {
Map<String, DateTimeZone> names = new HashMap<>(4);
names.put("CET", ZONE);
names.put("CEST", ZONE);
return names;
}
The validity of the time on the date is also validated: date.toDateTime() validates that the resulting DateTime would not fall in the gap at the spring-forward and throws an IllegalInstantException: if it would.
If the hours you receive in the string are always two digits, the format pattern string needs to specify this, so HH:mm z.
Please be aware that you are losing information in a corner case: If the time falls in the overlap at fall-back, the time zone abbreviation disambiguates, but the LocalDateTime that you produce is ambiguous. For example the date is 2021-10-31 and the time string is 2:20 CEST. Then we know that the time is in the summer time part of the year, that is, before the clocks are turned back. You return 2021-10-31T02:20:00.000, and the receiver won’t be able to tell whether to understand it as 2021-10-31T02:20:00.000+02:00 (summer time) or 2021-10-31T02:20:00.000+01:00 (standard time).

how to change the current date

my method accepts - hours, minutes, seconds and milliseconds separated by sign / as a string parameter
how can I add to the current date the parameters that come to the method.
Example 1: today, 02/10/2021, the method receives metnode data (10/10/10/10) - output - 02/10/2021 10:10:10
Example 2: today, 02/10/2021, the method receives metnode data (55/10/10/10) - output - 02/12/2021 07:10:10
That is, you need to add 55 hours 10 seconds 10 seconds and 10 milliseconds to the current date.
you cannot use the Calendar and StringTokenizer classes.
public void method(String s) {
s = s.replaceAll("/", "-");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss");
final LocalDateTime now = LocalDateTime.parse(s, formatter.withResolverStyle(ResolverStyle.LENIENT));
System.out.println(now);
}
i found the withResolverStyle (ResolverStyle.LENIENT) method
but did not understand how to use it.
A lenient DateTimeFormatter is enough
I don’t know if it’s the best solution. That probably depends on taste. It does use the ResolverStyle.LENIENT that you mentioned and generally works along the lines of the code in your question, only fixed and slightly simplified.
My formatter includes both date and time. This is necessary for surplus hours to be converted to days.
private static final DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-dd H/m/s/")
.appendValue(ChronoField.MILLI_OF_SECOND)
.toFormatter()
.withResolverStyle(ResolverStyle.LENIENT);
Next thing we need a string that matches the formatter. So let’s prepend the date to the time string that we already have got:
String timeString = "55/10/10/10";
LocalDate today = LocalDate.now(ZoneId.of("America/Regina"));
String dateTimeString = "" + today + ' ' + timeString;
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println(dateTime);
The output from my code when I ran it today (February 10) was:
2021-02-12T07:10:10.010
A different idea: use Duration
Edit: An alternative is to use the Duration class. A reason for doing that would be that it really appears that you are adding a duration rather than setting the time of day. A liability is that parsing your string into a Duration is a bit tricky. The Duration.parse method that we want to use only accepts ISO 8601 format. It goes like PT55H10M10.010S for a period of time of 55 hours 10 minutes 10.010 seconds. And yes, milliseconds need to be given as a fraction of the seconds.
String isoTimeString = timeString.replaceFirst("(/)(\\d+)$", "$100$2")
.replaceFirst("(\\d+)/(\\d+)/(\\d+)/0*(\\d{3})", "PT$1H$2M$3.$4S");
Duration dur = Duration.parse(isoTimeString);
LocalDateTime dateTime = LocalDate.now(ZoneId.of("Asia/Kathmandu"))
.atStartOfDay()
.plus(dur);
When I ran it just now — already February 11 in Kathmandu, Nepal — the output was:
2021-02-13T07:10:10.010
I am using two calls to replaceFirst(), each time using a regular expression. The first call simply adds some leading zeroes to the milliseconds. $1 and $2 in the replacement string give us what was matched by the first and the second group denoted with round brackets in the regular expression.
The second replaceFirst() call established the ISO 8601 format, which includes making sure that the milliseconds are exactly three digits so they work as a decimal fraction of the seconds.
Link: ISO 8601
Try this:
public void method(String s) {
String[] arr = s.split("/");
LocalDateTime now = LocalDateTime.of(
LocalDate.now(), LocalTime.of(0, 0))
.plusHours(Integer.parseInt(arr[0]))
.plusMinutes(Integer.parseInt(arr[1]))
.plusSeconds(Integer.parseInt(arr[2]))
.plusNanos(Integer.parseInt(arr[3]) * 1_000_000L);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss");
System.out.println(now.format(formatter));
}
Look into the LocalDateTime documentation. It offers various means for combining dates. Such as:
plus(amount, unit)
plusDays(days)
plusHours(hours)
plusMinutes(minutes)
just for simplicity , you can your LocalDateTime class. it is easy to understand. please refer to below code is used to add the hours, minuts, second and nanos to current Date Time.
this Date Time then can easy formatted by any format pattern as required.
public void addDateTime(int hours, int minuts, int seconds, int nanos) {
LocalDateTime adt = LocalDateTime.now();
System.out.println(adt);
adt = adt.plusHours(hours);
adt = adt.plusMinutes(minuts);
adt = adt.plusSeconds(seconds);
adt = adt.plusNanos(nanos);
System.out.println(adt);
}

Is resultant java.time code has more code statements compared to equivalent Calendar code

Recently, I try to port one of our old code base, from Calendar to java.time, as we need quite a number of arithmetic functionalities, which is only found in java.time.
If we use Calendar in our current code base, we need to perform a lot of conversion back-and-forth (From Calendar to Instant, From Instant back to Calendar), in the middle of our code.
To avoid such cumbersome conversion, we decide to eliminate usage of Calendar, and port them to equivalent java.time code.
I'm a bit skeptical on my port. As compared with Calendar code, it seems to
Create more temporary object instances within the while loop.
Requires more code statements.
Calendar code
// reminderCal is Calendar object.
long startTimestamp = getStartTimestamp();
reminderCal.setTimeInMillis(startTimestamp);
while (startTimestamp <= maxTimestamp) {
resultList.add(startTimestamp);
reminderCal.add(Calendar.DAY_OF_MONTH, 1);
startTimestamp = reminderCal.getTimeInMillis();
}
return resultList;
java.time code
// Epoch timestamp loopTs as initial input.
long startTimestamp = getStartTimestamp();
final ZoneId zoneId = ZoneId.systemDefault();
while (startTimestamp <= maxTimestamp) {
resultList.add(startTimestamp);
// More code, more temporary instances required compared
// with Calendar's version. Not sure we're doing the right
// way.
Instant instant = Instant.ofEpochMilli(startTimestamp);
LocalDateTime time = LocalDateTime.ofInstant(instant, zoneId);
time = time.plus(1, ChronoUnit.DAYS);
startTimestamp = time.atZone(zoneId).toInstant().toEpochMilli();
}
return resultList;
For the above code, I was wondering, are we doing the port correctly and optimized? Is there any room we can improve in our java.time's port?
Since you want date manipulations between times in a given time zone, you shouldn't use milliseconds nor LocalDateTime, but ZonedDateTime. And I would argue that your List should contain Instants instead of longs, but let's keep it that way for now:
long startTimestamp = getStartTimestamp();
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime maxDateTime = Instant.ofEpochMilli(maxTimestamp).atZone(zoneId);
ZonedDateTime loopDateTime = Instant.ofEpochMilli(loopTs).atZone(zoneId);
while (!loopDateTime.isAfter(maxDateTime)) {
tsList.add(loopDateTime.toInstant().toEpochMilli());
loopDateTime = loopDateTime.plusDays(1);
}
This is more concise, but also more readable. And all the Instant.ofEpochMilli() and toEpochMilli() calls wouldn't be needed if you wroked with Instants instead of longs.

Time Difference of two different timezone

I want to get the difference of current time (Which is IST) and the time which is stored in DB(EST). In order to that I am trying to convert current time to EST before calculating the difference. But its not working. In the following approach,
local time is not getting converted to EST only. Could you please suggest me the better way to do it ?
The return type of getModifiedDate is java.sql.Timestamp and the data type
of the column is DATE
Code :
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("EST"));
cal.setTimeInMillis(System.currentTimeMillis());
cal.getTimeInMillis() - emp.getModifiedDate().getTime();
I was trying to do it using SimpleDateFormat , But I am not sure how to proceed with that approach.
If you can provide the code snippet that will be helpful
You can try java.util.TimeZone
long now = System.currentTimeMillis();
long diff = TimeZone.getTimeZone("IST").getOffset(now) - TimeZone.getTimeZone("EST").getOffset(now);
getOffset - Returns the offset of this time zone from UTC at the specified date
If you have access to Java 8, then it may be just as easy to calculate the difference between the two dates directly, rather than adjusting to a target time zone first.
You could do this using ZonedDateTime from the java.time package:
// Our timestamp
Timestamp ts = emp.getModifiedDate();
// Convert timestamp to ZonedDateTime in the correct time zone
ZonedDateTime estTime = ts.toLocalDateTime().atZone(ZoneId.of("America/New_York"));
// Could pass in ZoneId.of("Asia/Kolkata") argument to now(...), but not required
// as "now" is the same instant in all time zones.
ZonedDateTime zonedNow = ZonedDateTime.now();
// Can use other ChronoUnit values if required.
long timeDiff = ChronoUnit.MILLIS.between(zonedNow, estTime);
// Use timeDiff as required
I suggest using the java.time API of JDK 8 which simplifies this to a great extent. Consider the following example:
Timestamp t = emp.getModifiedDate();
Duration.between(t.toInstant(), ZonedDateTime.now(ZoneId.of("Asia/Kolkata")).toInstant());
The timestamp retrieved from DB has been converted to Instant which is in UTC, similarly the current time in Asia/Kolkata zone has been converted to Instant and the Duration between the two has been calculated.You can retrieve the required information from the duration.
You can find it using java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
import java.time.Duration;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(formatDuration(diffBetweenTimeZones("Asia/Kolkata", "America/New_York")));
System.out.println(formatDuration(diffBetweenTimeZones("America/New_York", "Asia/Kolkata")));
// You can use the returned value to get the ZoneOffset which you can use for
// other processing e.g.
ZoneOffset offset = ZoneOffset.of(formatDuration(diffBetweenTimeZones("Asia/Kolkata", "America/New_York")));
System.out.println(offset);
System.out.println(OffsetDateTime.now(offset));
}
static Duration diffBetweenTimeZones(String tz1, String tz2) {
LocalDate today = LocalDate.now();
return Duration.between(today.atStartOfDay(ZoneId.of(tz1)), today.atStartOfDay(ZoneId.of(tz2)));
}
static String formatDuration(Duration duration) {
long hours = duration.toHours();
long minutes = duration.toMinutes() % 60;
String symbol = hours < 0 || minutes < 0 ? "-" : "+";
return String.format(symbol + "%02d:%02d", Math.abs(hours), Math.abs(minutes));
// ####################################Java-9####################################
// return String.format(symbol + "%02d:%02d", Math.abs(duration.toHoursPart()),
// Math.abs(duration.toMinutesPart()));
// ####################################Java-9####################################
}
}
Output:
+09:30
-09:30
+09:30
2021-03-24T19:52:29.474858+09:30
Learn more about the modern date-time API from Trail: Date Time.
Note that the java.util date-time API is outdated and error-prone. It is recommended to stop using it completely and switch to the modern date-time API*.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
TimeZone has two methods getRawOffet and getOffset that retrieves the offset of the time zone to UTC in milliseconds. The second one is adjusted for Daylight Saving Time and request the date to check if it is in effect.
TimeZone current = TimeZone.getDefault();
TimeZone db = TimeZone.getTimeZone("US/Eastern"); // or "EST5EDT", or "America/New_York"
System.out.printf("DB: %s Current: %s\n", db, current);
System.out.printf("Raw: %.1f h\n", (db.getRawOffset() - current.getRawOffset())/3_600_000D);
final long now = System.currentTimeMillis();
System.out.printf("DST: %.1f h\n", (db.getOffset(now) - current.getOffset(now))/3_600_000D);

Converting JODA UTC time to timezone

Using the following block of code I am trying to convert a UTC JODA time to a specified timezone using a string vale, e.g "Asia/Tokyo"
public void handleTimezoneConversion(TimesheetEntry timesheetEntry, String timezone) {
System.out.println("TO :"+timezone);
System.out.println(timesheetEntry.getStartDateTime());
LocalDateTime startDateTime = timesheetEntry.getStartDateTime();
startDateTime.toDateTime(DateTimeZone.forID(timezone));
timesheetEntry.setStartDateTime(startDateTime);
System.out.println(timesheetEntry.getStartDateTime());
LocalDateTime endDateTime = timesheetEntry.getEndDateTime();
endDateTime.toDateTime(DateTimeZone.forID(timezone));
timesheetEntry.setEndDateTime(endDateTime);
}
When i run it the time stays the same evn though there should be a noticeable difference.
Where am I going wrong, are my methods off course completely?
LocalDateTime's toDateTime() method returns a DateTime. In your code, you're calling toDateTime() but discarding the return value. Instead, you'll want to do something like this:
DateTime newDateTime = startDateTime.toDateTime(DateTimeZone.forID(timezone));

Categories

Resources