Java DateTimeFormatter Month Of Year Format - java

I am trying to convert an Instant to a String with the format like "10 Jul 2021, 10:00 PM".
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd LLL yyyy, hh:mm a");
String formattedDate = formatter.withZone(ZoneId.from(ZoneOffset.UTC)).format(instant);
It works as expected on my machine, but it comes out as "10 7 2021, 10:00 PM" in other environments.

Use MMM for month abbreviation and specify desired locale
Instant instant = Instant.ofEpochSecond(1_625_954_400);
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("dd MMM uuuu, hh:mm a", Locale.US);
String formattedDate = formatter.withZone(ZoneOffset.UTC).format(instant);
System.out.println(formattedDate);
Output:
10 Jul 2021, 10:00 PM
This should be stable across computers except that it may theoretically vary with different Java versions. I don’t expect it to.
What went wrong in your code?
By all likelihood the inconsistent results that you have observed are due to different locales. When not instructed otherwise, the one-arg DateTimeFormatter.ofPattern() gives you a formatter that is using the default locale of the JVM (usually taking from an operating system setting). This will give you very varied results on computers and JVMs with different language and region settings. To confuse things further locale data vary with Java version and locale provider setting (the java.locale.providers system property). On my Java 8 very many locales gave 7 as month from LLL and only German have Jul. On my Java 11 only the Vai language of Liberia gives 7 while many give Jul.
Format pattern letter L is for the stand-alone form of month name or abbreviation and should generally not be used when the month is part of a date as it is in your case. In most locales L and M give the same results, but there are locales where there’s a difference and on purpose.

Try this code: this will work 100%
DateFormat df = new SimpleDateFormat("dd-MMMM-yyyy HH:mm a");
Date date = new Date(System.currentTimeMillis());
String infi = df.format(date);
And the output be like
18-May-2021 11:31 PM

Related

How to convert a String data and time including month name to Date object in Java?

I want to convert the date in string to date object being the string "10h 57m 20s October 13 2020". How can be done? may replace firstly the h, m and s to get the format "10:57:20 October 13 2020"? As well, I tried the last format "10:57:20 October 13 2020" to get the date with DateTimeFormat and DateTimeFormatterBuilder() but is does not work with the month or it works but the hour coverts to 00:00:00.
Thanks
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work. Like Joop Eggen already wrote, put the letters that are part of your format in single quotes in the format pattern string:
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("H'h' m'm' s's' MMMM d y", Locale.ENGLISH);
This will allow you to parse like this:
String dateInString = "10h 57m 20s October 13 2020";
LocalDateTime dateTime = LocalDateTime.parse(dateInString, FORMATTER);
System.out.println(dateTime);
Output:
2020-10-13T10:57:20
You shouldn’t take any interest in the old-fashioned Date class. However, sometimes we need to pass a Date to a legacy API not yet upgraded to java.time. The conversion requires that we know the time zone assumed for the parsed date and time. For example:
ZoneId zone = ZoneId.of("America/Tegucigalpa");
Instant i = dateTime.atZone(zone).toInstant();
Date oldfashionedDate = Date.from(i);
System.out.println(oldfashionedDate);
Example output:
Tue Oct 13 10:57:20 CST 2020
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
You can place fixed letters in apostrophes.
"HH'h' mm'm' ss's' MMMM dd yyyy"
Furthermore hh is the 12 hour format to be combined wiht a AM/PM.
HH is the 24 hour format.
Also the locale must be correct, maybe explicitly set. Here English.

Converting from one time format to the other

Is it possible to convert this date string using Java time package
3-6-2017
to this format
"Mon Mar 6 00:00:00 EST 2017"
I created these two formatters, but which time instance should I use? I've tried LocalDate, LocalDateTime, and ZonedDateTime.
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("M-d-uuuu");
DateTimeFormatter convertedToFormat = DateTimeFormatter.ofPattern("EEE MMM dd hh:mm:ss zzz yyyy");
I believe that you have three issues:
To accept month in either 1 or 2 digits (like 3 for March and 11 for November) you need to specify one pattern letter M, not two. Similarly for day of month. So your input format pattern string should be M-d-uuuu (or just M-d-u). Edit: You also need d instead of dd in the “converted to” pattern.
To print hour of day (from 00 through 23) you need uppercase HH. Lowercase hh is for clock hour within AM or PM from 01 through 12.
Since your input string did not contain time of day, you need to specify time of day some other way. Similar for time zone since your “converted to” format contains zzz for time zone abbreviation.
So in code I suggest:
DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("M-d-uuuu");
DateTimeFormatter convertedToFormat = DateTimeFormatter.ofPattern("EEE MMM d HH:mm:ss zzz yyyy");
String input = "3-6-2017";
ZonedDateTime startOfDay = LocalDate.parse(input, inputFormat)
.atStartOfDay(ZoneId.of("America/New_York"));
String output = startOfDay.format(convertedToFormat);
System.out.println(output);
Output from my snippet is the desired:
Mon Mar 6 00:00:00 EST 2017
Or to answer your question a little more directly:
… which time instance should I use?
You need two of them: LocalDate for parsing your input and ZonedDateTime for formatting your output. And then a conversion between the two. The one-arg atStartOfDay method provides the conversion we need. (There is a trick for parsing directly into a ZonedDateTime using default values for time and time zone, but it’s more complicated.)
There are other time zones that will also produce EST as time zone abbreviation. Since your profile says you’re in Boston, I think that America/New_York is the one you want.

Java: Parse Date String with timezone abbreviations to Date object

I need to parse a date string with timezone to Date object. The input date string pattern is:
"MM/dd/yyyy hh:mm a z" (eg: 04/30/2018 06:00 PM IST).
I have used below given code. But it returns incorrect date as output.
new SimpleDateFormat("MM/dd/yyyy hh:mm a z").parse("04/30/2018 06:00 PM IST")
Current Output: "Mon Apr 30 09:00:00 PDT 2018".
Expected Output: "Mon Apr 30 05:30:00 PDT 2018.
That's because timezone's abbreviations such as IST are ambiguous. IST is used in India, Israel and Ireland, and SimpleDateFormat assumes some of them as default, in obscure and undocumented ways (AFAIK). Actually, according to javadoc: "support of abbreviations is for JDK 1.1.x compatibility only and full names should be used".
One way to make it work is to arbitrarily choose a timezone and set it in the formatter:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a z");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date = sdf.parse("04/30/2018 06:00 PM IST");
Always use names in the format Continent/Region, such as Asia/Kolkata. Those names are IANA's timezones names, and they are not ambiguous, so this make things work.
java.time API
If you're using Java 8 or higher, switch to the java.time API, which is much better. For Java 7 or lower, there's the Threeten Backport with the same classes and functionality.
In this API, you must set a list of all preferred timezones to be used in case of ambiguous names like IST:
// prefered zones
Set<ZoneId> preferredZones = new HashSet<>();
preferredZones.add(ZoneId.of("Asia/Kolkata"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date and time
.appendPattern("MM/dd/yyyy hh:mm a ")
// zone (use set of prefered zones)
.appendZoneText(TextStyle.SHORT, preferredZones)
// use English, because different locales can affect timezones names
.toFormatter(Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse("04/30/2018 06:00 PM IST", fmt);
If you still need to use java.util.Date, it's easy to convert:
// Java 8
Date d = Date.from(zdt.toInstant());
// Java 7 (Threenten Backport)
Date d = DateTimeUtils.toDate(zdt.toInstant());
The resultant Date object will not hold any timezone information. See the similar query in this stackoverflow thread
You might be getting the correct date but in your JVM's current timezone.
In case if you are using Java 8, then there's a provision of Date object with timezone. Look at ZonedDateTime, but for this you need a different kind of formatter while parsing (DateTimeFormatter)

Java 8 Date time formatter misbehaving

I have the following piece of code that is throwing a DateTimeParseException:
String dateString = "Jul 20 09:32:46"
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("L d HH:mm:ss");
return ZonedDateTime.parse(dateString, formatter);
According to the documentation, you will observe that Jul is the example for character L.
However, the exception message is:
java.time.format.DateTimeParseException: Text 'Jul' could not be parsed at index 0
What am I missing?
You have some issues here:
To correctly parse 'Jul' you have to use MMM instead of L (here explains why).
Your date string doesn't have a year. You can't create a ZonedDateTime without the year.
If is a Zoned date time, it has to include the time zone information too, which is not in your date string. You can use a LocalDateTime if you don't want to work with time zones.
Here are some alternatives:
With timezone:
String dateString = "Jul 20 2018 09:32:46+0000";
DateTimeFormatter formatter= DateTimeFormatter.ofPattern("MMM dd y H:mm:ssZ");
return ZonedDateTime.parse(dateString, formatter);
Without timezone:
String dateString = "Jul 20 2018 09:32:46";
DateTimeFormatter formatter= DateTimeFormatter.ofPattern("MMM dd y H:mm:ss");
return LocalDateTime.parse(dateString, formatter);
The answer by Juan Carlos Mendoza is correct. I will give my suggestions as a supplement: either improve your string to include year and time zone, or build a formatter that can parse your current string without them.
Improving your string
String dateString = "Jul 20 2018 09:32:46 America/Argentina/La_Rioja";
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("LLL d uuuu HH:mm:ss VV", Locale.ROOT);
System.out.println(ZonedDateTime.parse(dateString, formatter));
This prints
2018-07-20T09:32:46-03:00[America/Argentina/La_Rioja]
The same formatter will also parse Jul 20 2018 09:32:46 -08:30 into a ZonedDateTime of 2018-07-20T09:32:46-08:30.
First potential issue is the locale. If “Jul” is in English, give an English-speaking locale, or parsing will likely fail on computers with a language where the month of July is called something else. I recommend you always specify locale with your formatter. Even if you end up going for Locale.getDefault(). It will still tell the reader (and yourself) that you have made a conscious choice.
Next the documentation says that both M and L can give month as number/text and gives examples 7; 07; Jul; July; J. So this line is clearly relevant: “Number/Text: If the count of pattern letters is 3 or greater, use the Text rules above. Otherwise use the Number rules above.” Since “Jul” is text, you need 3 pattern letters or greater. “Less than 4 pattern letters will use the short form.” “Jul” is short, so we need exactly three letters.
The code above works with Java 9.0.4 no matter if I use MMM or LLL in the format pattern string. In jdk1.8.0_131 it works with MMM but funnily fails with LLL, this may be a bug (tested on a Mac). See Juan Carlos Mendoza’s for a treatment of the intended difference between M and L.
Build a formatter that works
String dateString = "Jul 20 09:32:46";
ZoneId zone = ZoneId.of("America/Argentina/La_Rioja");
DateTimeFormatter formatter = new DateTimeFormatterBuilder().appendPattern("LLL d HH:mm:ss")
.parseDefaulting(ChronoField.YEAR, Year.now(zone).getValue())
.toFormatter(Locale.ROOT)
.withZone(zone);
System.out.println(ZonedDateTime.parse(dateString, formatter));
This will parse the string from your question into 2018-07-20T09:32:46-03:00[America/Argentina/La_Rioja]. Please substitute your desired default time zone if it didn’t happen to coincide with the one I picked at random. Also substitute your desired year if you don’t want the current year.
Again my Java 8 requires MMM rather than LLL.

how to parse output of new Date().toString()

I need a date format (maybe SimpleDateFormat) that parses reliable the output I get when I call toString() on a Date object. Output on my german(!) system is: "Sun Dec 12 13:45:12 CET 2010", so it doesn't seem to honor locales, which seems to make it easy.
Anyone?
That format is specified in the Date#toString().
Converts this Date object to a String of the form:
dow mon dd hh:mm:ss zzz yyyy
So, in SimpleDateFormat pattern terms:
EEE MMM dd HH:mm:ss zzz yyyy
Unrelated to the problem, I wonder if it wasn't in first place a bad idea to use Date#toString() instead of SimpleDateFormat#format() to output dates. I would consider to fix it straight there.
BalusC gave you the correct format, you I'd say - don't. The toString() method must not be used for anything other than logging.
You can use SimpleDateFormat for both formatting and parsing.
TL;DR
Instant parsedBack = Instant.parse(Instant.now().toString());
System.out.println(parsedBack);
2019-05-30T08:36:47.966274Z
Use ISO 8601 and java.time
If your real goal is to serialize and deserialize a date and time (for data transfer or for persistence, for example), serialize to ISO 8601, the standard format for date and time data.
Skip the long outdated Date class. The modern Java date and time API known as java.time is so much nicer to work with. The class you need from it is probably Instant (this depends on your more exact requirements).
The two points go nicely hand in hand:
Instant i = Instant.now();
String s = i.toString();
Instant theSameInstant = Instant.parse(s);
The modern classes’ toString methods produce ISO 8601 format (e.g., 2018-01-11T10:59:45.036Z), and their parse methods read the same format back. So this snippet is all you need, and you get an instant equal to the first, with nanosecond precision.
If you cannot control the string you get, and you get the result from Date.toString(), the format pattern string in BalusC’s answer works with java.time too:
DateTimeFormatter dtf
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
Date d = new Date();
String s = d.toString();
Instant nearlyTheSameInstant = ZonedDateTime.parse(s, dtf).toInstant();
Some warnings, though:
Milliseconds from the original Date are lost since they are not in the string, leading to an inaccuracy of up to 999 milliseconds (which was why I named the variable nearlyTheSameInstant).
The era from the original Date is not in the string either. So if your original Date was in year 44 BCE, you will get the corresponding date in year 44 CE (AD) (in which case the variable name nearlyTheSameInstant was a lie anyway).
The time zone abbreviation in the string is often (most often?) ambiguous, so there is a great risk of getting the wrong time zone and hence a wrong time. To make matters worse, an ambiguous time zone abbreviation will be interpreted differently on different JVMs
It’s essential to provide a locale. Otherwise the JVM’s default locale will be used, and if it’s not English, parsing will fail. In the worst case you will see your code running fine for many years and suddenly it will break when one day someone runs it on a computer or device with a different locale setting. I use Locale.ROOT for “the locale neutral locale” or “don’t apply any locale specific processing”. It seems to be the correct approach here.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
you can use jdk8's DateTimeFormatter
DateTimeFormatter dtf
= DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
Date d = new Date();
String s = d.toString();
Instant nearlyTheSameInstant = ZonedDateTime.parse(s, dtf).toInstant();
Date nearlyTheSameInstantDate = Date.from(nearlyTheSameInstant);
DateTime dateTime = new DateTime(nearlyTheSameInstantDate);
String str = dateTime.toString("yyyy/MM/dd");
System.out.println("str = " + str);

Categories