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.
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 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
I have two strings that I want to convert into a particular date time format so I can do a comparison. Problem I have is that it errors out in the parse with an exception and I wonder if I am doing something wrong. Wanted to ask what is the best way to convert two different string dates into a single date format
SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy dd mm - HH:mm:ss");
String firstDateString= "11 May 2018 21:03:51 GMT";
String secondDateString= "dataStore.get("2018-05-11T21:03:51Z";
Date firstDateFormat =localDateFormat.parse(firstDateString);
Date secondDateFormat =localDateFormat.parse(secondDateString);
Problem I have is that it errors out in the parse with an exception
and I wonder if I am doing something wrong.
=> Yes you are doing it actually. You first need to parse the date into it's actual format and then format it into the desired format.
For example: for parsing and formatting 2018-05-11T21:03:51Z
DateFormat originalFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:MM:SS'z'", Locale.ENGLISH);
DateFormat targetFormat = new SimpleDateFormat("yyyy dd mm - HH:mm:ss");
Date date = originalFormat.parse("2018-05-11T21:03:51Z");
String formattedDate = targetFormat.format(date); // 2018 05 11 - 21:03:51
Here:
SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy dd mm - HH:mm:ss");
That format says: 4 year digits SPACE 2 day digits SPACE 2 month digits DASH and so on.
Thing is: neither your string dates:
"11 May 2018 21:03:51 GMT"
"2018-05-11T21:03:51Z"
Look like that. The first one is rather "dd M yyy ..." (doesnt start with year), and the second one uses "-" not " " as separator for the initial date.
Answer: you have to use a pattern that really matches the expected date strings, see here for the specs. And note for example that you will need to use M to match "May", the lowercase m is about digits, not words!
And note: the second example is an ISO date, and the DateTimeFormatter already has pre-defined formatters for those! (so be careful about re-inventing the wheel)
java.time
DateTimeFormatter firstFormatteer
= DateTimeFormatter.ofPattern("d MMM uuuu H:mm:ss z", Locale.ENGLISH);
String firstDateString = "11 May 2018 21:03:51 GMT";
String secondDateString = "2018-05-11T21:03:51Z";
Instant firstInstant = firstFormatteer.parse(firstDateString, Instant::from);
Instant seoncdInstant = Instant.parse(secondDateString);
System.out.println("The strings are parsed into " + firstInstant + " and " + seoncdInstant);
Output is:
The strings are parsed into 2018-05-11T21:03:51Z and 2018-05-11T21:03:51Z
Your strings from two services are in two different formats, and the best you can do is to handle them in two different ways. For the first, define a formatter that matches the format. The second is in ISO 8601 format. Instant parses this format without any explicit formatter, so here we don’t need to define one.
To compare do for example:
if (firstInstant.isBefore(seoncdInstant)) {
System.out.println("The first date and time comes first");
} else if (firstInstant.equals(seoncdInstant)) {
System.out.println("The date and time is the same");
}
The date and time is the same
The Instant class is the modern replacement for the Date class, it represents a moment in time.
The Date class was poorly designed and SimpleDateFormat notoriously troublesome, fortunately they are both long outdated. I recommend you avoid them and use java.time, the modern Java date and time API, instead.
Link: Oracle tutorial: Date Time explaining how to use java.time.
I'm trying to use Joda-Time library to convert a String date and time to Date but the result I get is not the expected.
From the server I get:
08/11/2017 12:30
10/11/2017 12:30
Joda converts it to:
2017-01-08T12:30:00.000+02:00
2017-01-10T12:30:00.000+02:00
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/mm/yyyy HH:mm:ss");
// add two :00 at the end for the seconds
startDate = startDate +":00";
DateTime start = formatter.parseDateTime(startDate);
System.out.println(start.toString());
endDate= endDate + ":00";
DateTime end = formatter.parseDateTime(endDate);
That's because you're using mm for the month, but the correct pattern is uppercase MM. Check the documentation for more details.
One more thing. If your input doesn't have the seconds (:00), you don't need to append it in the end of the input strings. You can simply create a pattern without it:
// "MM" for month, and don't use "ss" for seconds if input doesn't have it
DateTimeFormatter formatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm");
// parse input (without ":00" for the seconds)
DateTime start = formatter.parseDateTime("08/11/2017 12:30");
System.out.println(start.toString());
The output will be:
2017-11-08T12:30:00.000-02:00
Notice that the offset (-02:00) is different from yours. That's because DateTime uses the default timezone if you don't specify one.