From YearMonth(yyyy-MM) to YearMonth(yyyy-MMMM) [duplicate] - java

This question already has an answer here:
Generate & parse "Year-Month" values in text from Java
(1 answer)
Closed 6 years ago.
I have a variable:
YearMonth date;
where inside standing "2016-07", for example.
I want it to be still YearMonth, but with "2016 july"(note , there's no "-" separator), or, even better, "2016 luglio", that is italian Locale.
How to do it?
UPDATE
I tried with JackDaniels's method. It could actually work, as it gives me a string(str) with the right format of date. But I need to put that string again into my YearMonth variable. I tried with:
myVariable = YearMonth.parse(str);
but it returns me an error: java.time.format.DateTimeParseException: Text '2014 gennaio' could not be parsed at index 4
How do I solve this?

Use the new DateTimeFormatter to parse and format YearMonth directly and use Locale to set the locale you need.
Don't use SimpleDateFormat. That is part of the old Date API.
Try running the code to see if this is what you want in Codiva online compiler IDE.
YearMonth yearMonth = YearMonth.of(2016, 7);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MMMM",
new Locale("it", "IT"));
System.out.println(yearMonth.format(formatter));
Full working code in Codiva.

Related

Migrating to Java 8 DateTime [duplicate]

This question already has answers here:
How to get start and end range from list of timestamps?
(2 answers)
Date year value showing valid when invalid [duplicate]
(3 answers)
Closed 4 years ago.
I'm in the process of changing our existing SimpleDateFormat based code to use the new Java 8 LocalDateTime and ZonedDateTime classes.
I couldn't find an easy way to convert this piece.
Considering sample date and format.
String testDate = "2012-12-31T10:10:10-06:00";
String testFormat = "yyyy-MM-dd'T'HH:mm:ss";
Existing code,
SimpleDateFormat sdf = new SimpleDateFormat(testFormat);
System.out.println(sdf.parse(testDate));
This piece works for both the date value containing timezone offset like mentioned above or not. It ignores the timezone if provided and in both cases defaults to the system timezone.
However if I replace it with below code,
DateTimeFormatter df = DateTimeFormatter.ofPattern(testFormat);
LocalDateTime ldt = LocalDateTime.parse(testDate, df);
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
System.out.println(zdt.toString());
It fails for the above format. To get it to work, I have to get rid of the timezone bit in the date i.e. convert it to "2012-12-31T10:10:10" or then change the format to include timezone details i.e. 'z'.
So from my initial tests at least it seems the new classes are pretty strict from matching the format to the T unlike SimpleDateFormat. I even tried marking the DateTimeFormater.setLineant(), but that too didn't help. Or maybe there are some other classes which can work in this case, just that I am not aware of them.
To add more details as why i want to have the legacy behavior using the new API's. In our product we expose these API's which end customer can use, so the API in question accepts both the datetime value in string and the format and used "SimpleDateFormat". So i want existing behavior to continue even with the new API's just so that we continue to maintain backward compatibility.
For now the only solution for above example i have come up with is handle it as an exception case,
DateTimeFormatter df = DateTimeFormatter.ofPattern(testFormat);
LocalDateTime ldt = null;
try {
ldt = LocalDateTime.parse(testDate, df);
} catch (DateTimeParseException dtpException) {
ldt = ZonedDateTime.parse(testDate).toLocalDateTime();
}
if (ldt != null) zdt = ldt.atZone(ZoneId.systemDefault());
Can someone share some pointers around this use case?

Can I have more control on zone offset formatting at DateTimeFormatter [duplicate]

This question already has answers here:
SimpleDateFormat with TimeZone
(6 answers)
Closed 4 years ago.
Currently we are using
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
To format the time range to an external vendor for a range of data, for India, that formatter will give time like this:
2018-04-26T00:00:00.000+0530
However, my vendor say they cannot accept this format and it have to look like
2018-04-26T00:00:00.000+05:30
However, look like in DateTimeFormatter, whatever I choose Z/z/X/x, I don't get that format of offset. Just wonder is that a way to customize the offset to be HH:mm?
Or, I need to get the offset in second and work that our myself?
It is three x. Just tried with JavaRepl:
java.time.format.DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSxxx")
.withZone(java.time.ZoneId.systemDefault())
.format(java.time.Instant.now())
Results in
java.lang.String res10 = "2018-04-27T11:06:50.648+00:00"
After some trial and error, I saw that this is also documented in the API documentation of DateTimeFormatter but it is not easy to find (buried in a lot of other text):
Three letters outputs the hour and minute, with a colon, such as '+01:30'
DateTimeFormatter API Documentation

Formatting MonthDay using DateTimeFormatter.ofLocalizedDate [duplicate]

This question already has answers here:
How to format YearMonth and MonthDay depending on a Locale?
(3 answers)
Closed 5 years ago.
I am trying to format a MonthDay object in a way that I do not have to specify the order. I am trying to use a localized DateTimeFormatter.
I have this code:
LocalDate datetime = LocalDate.parse("2017-08-11", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
MonthDay monthday = MonthDay.from(datetime);
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.ENGLISH)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.GERMANY)));
System.out.println(monthday.format(DateTimeFormatter.ofPattern("MMMM dd").withLocale(Locale.forLanguageTag("UK"))));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)));
System.out.println(datetime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
// next line throws exception for java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
System.out.println(monthday.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
The first 3 prints will print as expected the translated Month and day, but it is always month and then day. It does not change the order because I am explicitly telling it the order.
The next two (before the exception) would print respectively:
Aug 11, 2017
11 серп. 2017
Notice how the day is either before or after the month depending on the locale passed to the function. How do I do this with a MonthDay object as the last line throws an exception when done in this way.
The other answers given so far describe the limitations of the standard DateTimeFormatter, see also the unsolved related JDK-issue. The suggested workaround to edit the localized date pattern by removing "y" etc. is tricky and might not work for all locales due to the existence of other localized literals inside the pattern.
However, you might also consider using external libraries which have a stronger focus on internationalization issues and have the capability to format a month-day-object using just the locale information. So the locale determines the order of field components and also dots, spaces or other special literals (like in Chinese).
Here two options with the necessary type conversions related to your system timezone:
ICU4J
MonthDay md = MonthDay.now();
GregorianCalendar gcal =
new GregorianCalendar(
2000, // avoids possible leap year problems
md.getMonthValue() - 1,
md.getDayOfMonth()
);
DateFormat df =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("en")
);
System.out.println(df.format(gcal.getTime())); // Aug 15
DateFormat df2 =
DateFormat.getInstanceForSkeleton(
DateFormat.ABBR_MONTH_DAY,
Locale.forLanguageTag("de")
);
System.out.println(df2.format(gcal.getTime())); // 15. Aug.
DateFormat df3 =
DateFormat.getInstanceForSkeleton(DateFormat.MONTH_DAY, Locale.forLanguageTag("zh"));
System.out.println(df3.format(gcal.getTime())); // 8月15日
Time4J
MonthDay md = MonthDay.now();
ChronoFormatter<AnnualDate> cf1 =
ChronoFormatter.ofStyle(DisplayMode.SHORT, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf1.format(AnnualDate.from(md))); // 15.8.
ChronoFormatter<AnnualDate> cf2 =
ChronoFormatter.ofStyle(DisplayMode.MEDIUM, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf2.format(AnnualDate.from(md))); // 15.08.
ChronoFormatter<AnnualDate> cf3 =
ChronoFormatter.ofStyle(DisplayMode.LONG, Locale.ENGLISH, AnnualDate.chronology());
System.out.println(cf3.format(AnnualDate.from(md))); // Aug 15
ChronoFormatter<AnnualDate> cf4 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.GERMAN, AnnualDate.chronology());
System.out.println(cf4.format(AnnualDate.from(md))); // 15. August
ChronoFormatter<AnnualDate> cf5 =
ChronoFormatter.ofStyle(DisplayMode.FULL, Locale.CHINESE, AnnualDate.chronology());
System.out.println(cf5.format(AnnualDate.from(md))); // 8月15日
Disclaimer: Time4J has been written by myself to fill gaps or to improve other features of JSR-310 (java.time-package).
MonthDay does not store the year information and the FormatStyle.MEDIUM requires a year value, thats why the formatter is not finding the field YearOfEra same occurs if you use YearMonth with same FormatStyle but now for the missing field DayOfMonth.
MonthDay API
This class does not store or represent a year, time or time-zone. For example, the value "December 3rd" can be stored in a MonthDay.
You could transform monthday to an Instant or simply use the datetime.
ofLocalizedDate returns a formatter for the date, so it formats the day, month and year fields, so the object being formatted needs to have all the three fields. MonthDay doesn't have the year field, that's why it throws a UnsupportedTemporalTypeException.
If you want to print the whole date (with day, month and year), you must add the year to the MonthDay object. You can use the atYear method for that:
System.out.println(monthday.atYear(2017).format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"))));
This will output:
11 серп. 2017
If you want the current year, just use Year.now().getValue() instead of 2017.
You can also use datetime.getYear(), if you want the same year of the LocalDate - or use the datetime instead of the monthday.
If you want to print just the day and month, you'll have to do some workarounds.
As the localized formatters are built-in in the JDK (and there seems to be no way to change them), you don't have a direct way of doing it, though there are some alternatives.
One (ugly) solution is to set a year and then remove it from the formatted String:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag("UK"));
// set year to 2017, then remove "2017" from the formatted string
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").trim());
The output is:
11 серп.
The boring part is to remove all extra characters that might exist in each locale. For the English locale, I also had to remove the ,:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH);
// remove the year (2017) and the "," from the output
System.out.println(monthday.atYear(2017).format(formatter).replace("2017", "").replace(",", "").trim());
The output is:
Aug 11
You'll have to check all the extra characters (such as ,) for all locales, and remove them from the output. Or just use ofPattern with fixed non-locale specific patterns (as you did in your first 3 tests).
As #BasilBourque's noticed in the comments, I'm assuming that the year is at the beggining or end of the pattern. If the year is in the middle, there will be some extra spaces in the final result, which can be removed with .replaceAll("\\s{2,}", " ") (2 or more spaces are replaced by just one).
Another alternative (as suggested by #JodaStephen comment) is to use a DateTimeFormatterBuilder to get the localized date pattern.
Then I remove the year from the pattern, replacing y and u (the patterns used for the year), and also remove some other characters (like , and extra spaces).
With the resulting pattern (without the year), I create a DateTimeFormatter with the specified locale and format the MonthDay:
// get date pattern for the specified locale
String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(FormatStyle.MEDIUM, null, IsoChronology.INSTANCE, Locale.forLanguageTag("UK"));
pattern = pattern
// remove the year (1 or more occurrences of "y" or "u")
.replaceAll("[yu]+", "")
// replace "," (you can change this to remove any other characters you want)
.replaceAll(",", "")
// replace 2 or more spaces with just one space and trim to remove spaces in the start or end
.replaceAll("\\s{2,}", " ").trim();
// create formatter for the pattern and locale
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern, Locale.forLanguageTag("UK"));
System.out.println(monthday.format(fmt));
The output will be:
11 серп.
Just reminding that this example might be incomplete, because there are some locales that uses /, - and other characters as separators and you must remove them from the final result. Check all the locales you're working with and remove the characters accordingly.
Another corner-case not covered by this is when you have y or u as literals (inside '): in this case they shouldn't be removed. Anyway, you'll have to check the formats for all locales you're working with and handle each case accordingly.

Java Date changing format [duplicate]

This question already has answers here:
java.util.Date format conversion yyyy-mm-dd to mm-dd-yyyy
(8 answers)
Closed 5 years ago.
I am trying to change the format of Date objects, I am trying to do it in this way:
for(Date date : dates){
DateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String formatterDate = formatter.format(date);
Date d = formatter.parse(formatter.format(date));
}
But this does not have any effect on the d object, it is still with the old format, can't really understand why it is like that.
Please try to keep two concepts apart: your data and the presentation of the data to your user (or formatting for other purposes like inclusion in JSON). An int holding the value 7 can be presented as (formatted into) 7, 07, 007 or +7 while still just holding the same value without any formatting information — the formatting lies outside the int. Just the same, a Date holds a point in time, it can be presented as (formatted into) “June 1st 2017, 12:46:01.169”, “2017/06/01” or “1 Jun 2017” while still just holding the same value without any formatting information — the formatting lies outside the Date.
Depending on your requirements, one option is you store your date as a Date (or better, an instance of one of the modern date and time classes like LocalDate) and keep a formatter around so you can format it every time you need to show it to the user. If this won’t work and you need to store the date in a specific format, then store it as a String.
Java 8 (7, 6) date and time API
Now I have been ranting about using the newer Java date and time classes in the comments, so it might be unfair not to show you that they work. The question tries to format as yyyy-MM-dd, which we may do with the following piece of code.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu/MM/dd");
for (LocalDate date : localDates) {
String formatterDate = date.format(dateFormatter);
System.out.println(formatterDate);
}
In one run I got
2017/05/23
2017/06/01
Should your objects in the list have other types than LocalDate, most other newer date and time types can be formatted in exactly the same way using the same DateTimeFormatter. Instant is a little special in this respect because it doesn’t contain a date, but you may do for example myInstant.atZone(ZoneId.of("Europe/Oslo")).format(dateFormatter) to obtain the date it was/will be in Oslo’s time zone at that instant.
The modern classes were introduced in Java 8 and are enhanced a bit in Java 9. They have been backported to Java 6 and 7 in the ThreeTen Backport with a special edition for Android, ThreeTenABP. So I really see no reason why you should not prefer to use them in your own code.
Try this one.
String formattedDate = null;
SimpleDateFormat sdf = new SimpleDateFormat(format you want);
formattedDate = sdf.format( the date you want to format );
return formattedDate;
some not best solution, but it works: this method will convert Date object to String of any pattern you need
public static void format(Date date){
String pattern = "MMM d yyyy";
LocalDateTime localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String result = formatter.format(localDate);
// new Date() -> Jun 1 2017
}
SimpleDateFormat is useful while converting Date to String or vice-versa. java.util.Date format will always remain same. If you want to display it in standalone application then use date.getxxx() methods and choose your design.

Best way to increment the date in a String URL? [duplicate]

This question already has answers here:
How to add days to a date in Java
(3 answers)
Closed 7 years ago.
So I have a URL that contains date=2016-01-25 somewhere in between. My goal is, when a user enters the URL and n days (in a GUI application's text fields), it should go into a loop of n times and increment the date from the URL. That also means it goes to the next month if it is 30/31. Anyone have an optimized approach to this?
Assuming you are using Java 8, you can use the java.time.LocalDate class to parse, add days, and convert back to a string. Here's an example:
String date = "2016-01-25";
LocalDate localDate = LocalDate.parse(date);
localDate = localDate.plusDays(15);
System.out.println(localDate); // Prints "2016-02-09"
To add to the Java 8 solutions, if you're using an earlier version of Java you can use JodaTime's LocalDate class to accomplish the same thing. Syntax will be the same as in Java 8.
You would need to parse the date string out of the URL, using something like regex and then create a Date object increment your date and rebuild the URL.
Java's Date primitives such as LocalDate have support for "plusDays(int n)"

Categories

Resources