I had this function that convert string type of date to unix timestamp, how to convert the result to timeInSeconds and offsetInNanos
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd-HH-mm-ss");
String dateTimeString = "2016-06-21-10-19-22";
LocalDate date = LocalDate.parse(dateTimeString, formatter);
ZonedDateTime resultado = date.atStartOfDay(ZoneId.of("UTC"));
Instant i = resultado.toInstant();
long timeInSeconds = i.getEpochSecond();
int nanoAdjustment = i.getNano();
System.out.println("" + timeInSeconds + " seconds " + nanoAdjustment + " nanoseconds");
result is 1466467200 seconds 0 nanoseconds
but the correct answer seems to be 1466504362 seconds
Edit
result is 1466467200 seconds 0 nanoseconds
but the correct answer seems to be 1466504362 seconds
I think it convert "2016-06-21-10-19-22" to 2016-06-21T00:00:00+00:00,
how to solve this problem, to convert both date with time and date
without time to correct timeInSeconds?
You are absolutely correct, that is what it does, This is because in your new code in the question you are
Only parsing the date part. You are parsing into a LocalDate, which is a date without time of day, so the time of day in the string is being ignored.
Then calling atStartOfDay(). This makes sure that the time of day is set to — as the method name says — the start of the day, in this case in UTC, so 00:00:00 UTC.
To solve: instead parse into a LocalDateTime so you get both date and time.
LocalDateTime date = LocalDateTime.parse(dateTimeString, formatter);
OffsetDateTime resultado = date.atOffset(ZoneOffset.UTC);
The rest of the code is the same. Now the output is:
1466504362 seconds 0 nanoseconds
This is the result you said you expected. While a ZonedDateTime would have worked too, for UTC it’s overkill, I recommend you use OffsetDateTime as I am showing.
For how to parse a string that may or may not have time of day in it, see some of the questions that I link to at the bottom.
Original answer: java.time
I suppose that by offset in nanos you meant nano adjustment, nanosecond part or nano of second (not offset from UTC). With java.time, the modern Java date and time API, it’s straightforward:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"MMM dd yyyy HH:mm:ss.SSS zzz", Locale.ENGLISH);
String dateTimeString = "Jun 13 2003 23:11:52.454 UTC";
Instant i = ZonedDateTime.parse(dateTimeString, formatter)
.toInstant();
long timeInSeconds = i.getEpochSecond();
int nanoAdjustment = i.getNano();
System.out.println("" + timeInSeconds + " seconds " + nanoAdjustment + " nanoseconds");
Output is:
1055545912 seconds 454000000 nanoseconds
I just did what deHaar said in the comments.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Questions on parsing dates with and without times:
Convert date time string like Joda DateTime(String) with Java 8
Parsing an ISO 8601 date in Java8 when all fields (including separators, but not including years) are optional
Related
I have to find out number of days between a given Time and current time. Given time is in ISO format and one example is "2021-01-14 16:23:46.217-06:00".
I have tried it using "java.text.SimpleDateFormat" but it's not giving me accurate results.
In Below Given date, for today's time I am getting output as "633" Days which isn't correct. somehow after parsing it is taking date as "21 december 2020" which isn't correct
String TIMESTAMP_FORMAT = "YYYY-MM-DD hh:mm:ss.s-hh:mm" ;
int noOfDays = Utility.getTimeDifferenceInDays("2021-01-14 16:23:46.217-06:00", TIMESTAMP_FORMAT);
public static int getTimeDifferenceInDays(String timestamp, String TIMESTAMP_FORMAT) {
DateFormat df = new SimpleDateFormat(TIMESTAMP_FORMAT);
try {
Date date = df.parse(timestamp);
long timeDifference = (System.currentTimeMillis() - date.getTime());
return (int) (timeDifference / (1000*60*60*24));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}
Looking for a better solution which gives me correct number of days. Thanks
Use java.time API
Classes Date and SimpleDateFormat are legacy.
Since Java 8 (which was released 10 years ago) we have a new Time API, represented by classes from the java.time package.
To parse and format the data, you can use DateTimeFormatter. An instance of DateTimeFormatter can be obtained via static method ofPattern(), or using DateTimeFormatterBuilder.
ofPattern():
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSXXX");
DateTimeFormatterBuilder:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss.") // main date-time part
.appendValue(ChronoField.MILLI_OF_SECOND, 3) // fraction part of second
.appendOffset("+HH:MM", "+00:00") // can be substituted with appendPattern("zzz") or appendPattern("XXX")
.toFormatter();
The string "2021-01-14 16:23:46.217-06:00", which you've provided as an example, contains date-time information and UTC offset. Such data can be represented by OffsetDateTime.
To get the number of days between two temporal objects, you can use ChronoUnit.between() as #MC Emperor has mentioned in the comments.
That's how the whole code might look like:
String toParse = "2021-01-14 16:23:46.217-06:00";
OffsetDateTime dateTime = OffsetDateTime.parse(toParse, formatter);
System.out.println("parsed date-time: " + dateTime);
Instant now = Instant.now();
long days = ChronoUnit.DAYS.between(dateTime.toInstant(), now);
System.out.println("days: " + days);
Output:
parsed date-time: 2021-01-14T16:23:46.217-06:00
days: 615
Note that since in this case you need only difference in days between the current date instead of OffsetDateTime you can use LocalDateTime, UTC offset would be ignored while parsing a string. If you decide to do so, then the second argument passed to ChronoUnit.between() should be also of type LocalDateTime.
Getting an Unparseable date error while calculating difference between Current date/time and Start date/time for an user.
Error: java.text.ParseException: Unparseable date: "09/11/20 00:00:00 AM CDT" at java.base/java.text.DateFormat.parse(DateFormat.java:395)
I get this error at line no.8, which is
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
'dateDifference' is a library used to calculate the difference between the current date/time and the start date/time of an user.
if(link.getAttribute("lastLogonTimeStamp")== null){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
System.out.println(" +++++ Output +++++" + output);
SimpleDateFormat sdf1 = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
String output2 = sdf1.format((sdf1.parse(startDate)).getTime());
System.out.println(" +++++ Start Date +++++" + output2);
int diff = dateDifference(output2);
System.out.println(" +++++ Difference +++++" + diff);
if(diff>0){
System.out.println("Start Date is not a Future Date :" + startDate);
bw.write(id.getName()+","+ntID+","+id.getFirstname() +" "+id.getLastname() +","+id.getEmail()+ "," + id.getAttribute("empType")+ "," +lastLoginDt+ ","+mgrName+","+(String)id.getAttribute("startDate")+","+(String)id.getAttribute("title")+"\n");
count++;
}
}
tl;dr
I would not accept such a poor input string into my own app. But if you insist, you can try to parse ambiguous input such as CDT but this is a guessing game that may fail depending on the input.
ZonedDateTime.parse(
"09/11/20 00:00:00 AM CDT" ,
DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" )
)
Parsing
CDT is not a real time zone. It is a localized indicator of whether Daylight Saving Time (DST) is effect.
Do not use localized formats for data exchange. Use localized values only for presentation to the user. For data exchange, use only ISO 8601 standard formats. The standard was invented for just that purpose, data exchange. The java.time classes use the standard formats by default when parsing/generating strings, so no need to specify formatting patterns.
Do not use Calendar and SimpleDateFormat classes. These terrible date-time classes are now legacy, years ago supplanted by the modern java.time classes defined in JSR 310. Search to learn more as this has been covered many many times already on Stack Overflow.
You can ask DateTimeFormatter class to guess what CDT might mean. But those pseudo-zone values are not standardized, and are not even unique! For example CST might mean "China Standard Time" or might mean "Central Standard Time" (in North America).
I recommend against accepting such poor inputs as yours, as playing guessing games in your code makes for unreliable apps. But if you insist:
String input = "09/11/20 00:00:00 AM CDT";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uu HH:mm:ss a z" );
ZonedDateTime zdt = ZonedDateTime.parse( input , f );
zdt.toString() = 2020-09-11T00:00-05:00[America/Chicago]
The text generated by ZonedDateTime#toString is actually an extension to the ISO 8601 standard format, appending the name of the zone in square brackets.
Calculating elapsed time
Apparently you want to calculate the amount of time elapsed between the moment represented by your input and the current moment.
To calculate elapsed time in terms of hours-minutes-seconds, use Duration while capturing the current moment as seen in UTC (an offset from UTC of zero hours-minutes-seconds).
Duration elapsed = Duration.between( zdt.toInstant() , Instant.now() ) ;
To calculate elapsed time in terms of years-months-days, use Period. Access the time zone contained in our ZonedDateTime to get the same timeframe.
Period elapsed = Period.between( zdt , ZonedDateTime.now( zdt.getZone() ) ;
I have rewritten the code in the below format and that worked.
if(lastLogon == null || lastLogon.equalsIgnoreCase("never")){
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
Calendar cur_time = Calendar.getInstance();
cur_time.setTime(new Date());
String output = sdf.format(cur_time.getTime());
SimpleDateFormat dateParser = new SimpleDateFormat("MM/dd/yy HH:mm:ss a zzz");
Date date = dateParser.parse(startDate);
SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyyMMddHHmmss");
String output2 = dateFormatter.format(date);
int diff = dateDifference(output2);
if(diff>0){}
I want a DateFormatter in java so that i can specify some special character as well as digits in a date expression. For ex :
String dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
Here dd is used to specify the day of month which is numeric.
But i have a requirement to create a date as below :
String stringDate = "2017-12-??T00:00Z";
SimpleDateFormat formatter = new SimpleDateFormat(dateFormat);
formatter.parse(stringDate);
I get an unparseable exception as the DAY specified here is ?? . Is there any workaround for this or shall i have to write a new parser ?
Thanks
Try escaping the additional literals using single quote
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-'??T'HH:mm:ss.SSS zzz");
Also the value and the format given should match(Can edit the string date as required), in your case following syntax will work.
String stringDate = "2017-12-??T00:00Z";
Date date = (new SimpleDateFormat("yyyy-MM-'??T'HH:mmZ")).parse(stringDate.replaceAll("Z$", "+0000"));
System.out.println("date: " + (new SimpleDateFormat("yyyy-MM-dd'??T'HH:mmZ")).format(date));
Please note that 'Z' indicates that the timezone conforms to the RFC 822 time zone standard as well.
Edit: Consider a scheduler. Your comment may sound like what you need is a scheduler, for example Quartz scheduler. I include a link at the bottom. Then convert user input not to a YearMonth, OffsetDateTime or any other date-time object (because they don’t fit), but into a syntax that your scheduler can accept.
Original answer
I am giving you a couple of suggestions. It’s with reservation though: I don’t understand why you want this, not even exactly what you want, so these suggestions may not be the right ones for you.
One suggestion I am pretty sure of, though: do use java.time, the modern java date and time API, for your date and time work. It is so much nicer to work with than the old, poorly designed and long outdated date-time classes that include the notoriously troublesome SimpleDateFormat class.
Parsing year and month: If you just want the year and the month from a string that has question marks instead of the day of month, parse into a YearMonth:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-'??T'HH:mmX");
String stringDate = "2017-12-??T00:00Z";
YearMonth ym = YearMonth.parse(stringDate, formatter);
System.out.println("Year and month are " + ym);
Output from this snippet is:
Year and month are 2017-12
Parsing all information from the string: If you need time of day and offset from the same string too, just parse the string once and get the various information from the parse result:
TemporalAccessor parsed = formatter.parse(stringDate);
YearMonth ym = YearMonth.from(parsed);
System.out.println("Year and month are " + ym);
LocalTime time = LocalTime.from(parsed);
System.out.println("Time of day is " + time);
ZoneOffset offset = ZoneOffset.from(parsed);
System.out.println("UTC offset is " + offset);
Year and month are 2017-12
Time of day is 00:00
UTC offset is Z
Using a default day of month: If you know what day of month you want instead of the question marks, specify it as a default value:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-'??T'HH:mmX")
.parseDefaulting(ChronoField.DAY_OF_MONTH, 23)
.toFormatter();
String stringDate = "2017-12-??T00:00Z";
OffsetDateTime dateTime = OffsetDateTime.parse(stringDate, formatter);
System.out.println("Date and time is " + dateTime);
Date and time is 2017-12-23T00:00Z
Accepting both numbers and question marks: If the date can be given as either numeric or question marks, use optional parts in the format pattern strings. Such are enclosed in square brackets:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("uuuu-MM-[??][dd]'T'HH:mmX")
.parseDefaulting(ChronoField.DAY_OF_MONTH, 23)
.toFormatter();
String stringDate = "2017-12-??T00:00Z";
OffsetDateTime dateTime = OffsetDateTime.parse(stringDate, formatter);
System.out.println("Date and time is " + dateTime);
stringDate = "2018-02-16T00:00Z";
dateTime = OffsetDateTime.parse(stringDate, formatter);
System.out.println("Date and time is " + dateTime);
Date and time is 2017-12-23T00:00Z
Date and time is 2018-02-16T00:00Z
Tutorial links
Cron Trigger Tutorial from the Quartz Scheduler documentation.
Oracle tutorial: Date Time explaining how to use java.time.
Java 8 has a completely new API for date and time. One of the most useful classes in this API is LocalDateTime, for holding a timezone-independent date-with-time value.
There are probably millions of lines of code using the legacy class java.util.Date for this purpose. As such, when interfacing old and new code there will be a need for converting between the two. As there seems to be no direct methods for accomplishing this, how can it be done?
Short answer:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
Explanation:
(based on this question about LocalDate)
Despite its name, java.util.Date represents an instant on the time-line, not a "date". The actual data stored within the object is a long count of milliseconds since 1970-01-01T00:00Z (midnight at the start of 1970 GMT/UTC).
The equivalent class to java.util.Date in JSR-310 is Instant, thus there are convenient methods to provide the conversion to and fro:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
A java.util.Date instance has no concept of time-zone. This might seem strange if you call toString() on a java.util.Date, because the toString is relative to a time-zone. However that method actually uses Java's default time-zone on the fly to provide the string. The time-zone is not part of the actual state of java.util.Date.
An Instant also does not contain any information about the time-zone. Thus, to convert from an Instant to a local date-time it is necessary to specify a time-zone. This might be the default zone - ZoneId.systemDefault() - or it might be a time-zone that your application controls, such as a time-zone from user preferences. LocalDateTime has a convenient factory method that takes both the instant and time-zone:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
In reverse, the LocalDateTime the time-zone is specified by calling the atZone(ZoneId) method. The ZonedDateTime can then be converted directly to an Instant:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
Note that the conversion from LocalDateTime to ZonedDateTime has the potential to introduce unexpected behaviour. This is because not every local date-time exists due to Daylight Saving Time. In autumn/fall, there is an overlap in the local time-line where the same local date-time occurs twice. In spring, there is a gap, where an hour disappears. See the Javadoc of atZone(ZoneId) for more the definition of what the conversion will do.
Summary, if you round-trip a java.util.Date to a LocalDateTime and back to a java.util.Date you may end up with a different instant due to Daylight Saving Time.
Additional info: There is another difference that will affect very old dates. java.util.Date uses a calendar that changes at October 15, 1582, with dates before that using the Julian calendar instead of the Gregorian one. By contrast, java.time.* uses the ISO calendar system (equivalent to the Gregorian) for all time. In most use cases, the ISO calendar system is what you want, but you may see odd effects when comparing dates before year 1582.
Here is what I came up with ( and like all Date Time conundrums it is probably going to be disproved based on some weird timezone-leapyear-daylight adjustment :D )
Round-tripping: Date <<->> LocalDateTime
Given: Date date = [some date]
(1) LocalDateTime << Instant<< Date
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
(2) Date << Instant << LocalDateTime
Instant instant = ldt.toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
Example:
Given:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
(1) LocalDateTime << Instant<< Date:
Create Instant from Date:
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);
Create Date from Instant (not necessary,but for illustration):
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
Create LocalDateTime from Instant
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);
(2) Date << Instant << LocalDateTime
Create Instant from LocalDateTime:
instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);
Create Date from Instant:
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
The output is:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Instant from Date:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
LocalDateTime from Instant:
2013-11-01T14:13:04.574
Instant from LocalDateTime:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Much more convenient way if you are sure you need a default timezone :
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
The fastest way for LocalDateTime -> Date is:
Date.from(ldt.toInstant(ZoneOffset.UTC))
Everything is here : http://blog.progs.be/542/date-to-java-time
The answer with "round-tripping" is not exact : when you do
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
if your system timezone is not UTC/GMT, you change the time !
the following seems to work when converting from new API LocalDateTime into java.util.date:
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
the reverse conversion can be (hopefully) achieved similar way...
hope it helps...
If you are on android and using threetenbp you can use DateTimeUtils instead.
ex:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
you can't use Date.from since it's only supported on api 26+
I'm not sure if this is the simplest or best way, or if there are any pitfalls, but it works:
static public LocalDateTime toLdt(Date date) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
ZonedDateTime zdt = cal.toZonedDateTime();
return zdt.toLocalDateTime();
}
static public Date fromLdt(LocalDateTime ldt) {
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
GregorianCalendar cal = GregorianCalendar.from(zdt);
return cal.getTime();
}
I think below approach will solve the conversion without taking time-zone into consideration.
Please comment if it has any pitfalls.
LocalDateTime datetime //input
public static final DateTimeFormatter yyyyMMddHHmmss_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatDateTime = datetime.format(yyyyMMddHHmmss_DATE_FORMAT);
Date outputDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(formatDateTime); //output
This question already has answers here:
Java 8 Date and Time: parse ISO 8601 string without colon in offset [duplicate]
(4 answers)
Closed 3 years ago.
StrDate = "2011-07-19T18:23:20+0000";
How can I get an epoch time for the above date format in android
also I would like to know how to convert a epoch time to the above date format.
I would appreciate a direct answer with an example.
Example code using Joda-Time 2.3.
Unix time is number of seconds since beginning of 1970 in UTC/GMT.
How can I get an epoch time for the above date format in android
DateTime dateTimeInUtc = new DateTime( "2011-07-19T18:23:20+0000", DateTimeZone.UTC );
long secondsSinceUnixEpoch = ( dateTimeInUtc.getMillis() / 1000 ); // Convert milliseconds to seconds.
…and…
how to convert a epoch time to the above date format.
String dateTimeAsString = new DateTime( secondsSinceUnixEpoch * 1000, DateTimeZone.UTC ).toString();
To dump those values to the console…
System.out.println( "dateTimeInUtc: " + dateTimeInUtc );
System.out.println( "secondsSinceUnixEpoch: " + secondsSinceUnixEpoch );
System.out.println( "dateTimeAsString: " + dateTimeAsString );
Bonus: Adjust to another time zone.
DateTime dateTimeMontréal = dateTimeInUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
You should use SimpleDateFormat. That class both supports formatting, and parsing.
Sample code:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ssZZZZ");
Date gmt = formatter.parse("2011-07-19T18:23:20+0000");
long millisecondsSinceEpoch0 = gmt.getTime();
String asString = formatter.format(gmt);
Note that a Date instance in Java, always represent milliseconds since epoch 0, in UTC/GMT, but it is printed in local time when you print it.
To answer your question a bit late but Joda-Time will be able to handle both in a simply and clean way.
Using Joda-Time
1.Epoch time to Date
Where date is your epoch time
DateTime dateTime = new DateTime(date*1000L);
System.out.println("Datetime ..." + dateTime);
Datetime from Epoch ...2014-08-01T13:00:00.000-04:00
2.Date to epoch
DateTime fromDate = new DateTime("2011-07-19T18:23:20+0000");
long epochTime = fromDate.getMillis();
System.out.println("Date is.." + fromDate + " epoch of date " + epochTime);
Date is..2011-07-19T14:23:20.000-04:00 epoch of date 1311099800000