Java printf with date and month - java

System.out.printf("Time: %d-%d %02d:%02d" +
calendar.get(Calendar.DAY_OF_MONTH),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE);
That is the code a friend showed me, but how do I get the date to appear in a Format like November 1?

This is how to do it:
DateFormat dateFormat = new SimpleDateFormat( "MMMMM d" );
Calendar calendar = new GregorianCalendar(); // The date you want to format
Date dateToFormat = calendar.getTime();
String formattedDate = dateFormat.format( dateToFormat );
System.out.println( formattedDate );

Date d = new Date();
System.out.printf("%s %tB %<td", "Today", d);
// output :
// Today november 01
%tB for Locale-specific full month name, e.g. "January", "February".
%<td d for Day of month, formatted as two digits with leading zeros as necessary, < for reuse the last parameter.

The DateFormat answer is the way to do this. The printf answer is also good although does not provide locale-specific formats (it provides language-specific names but does not use e.g. the day/month/year ordering that the current locale uses).
You asked in a comment:
Can I do it with the calendar.get(Calendar.MONTH) etc method? Or do I have to use date format?
You don't have to use the other methods here, but if you want to use the Calender fields, it is up to you to convert the numeric values they provide to strings like "Tuesday" or "November". For that you can use the built in DateFormatSymbols, which provides internationalized strings from numbers for dates, in the form of String arrays, which you can use the Calendar fields to index in to. See How can I convert an Integer to localized month name in Java? for example.
Note you can use DateFormat.getDateInstance() to retrieve a pre-made format for the current locale (see the rest of those docs, there are also methods for getting pre-made time-only or date+time formats).
Basically you have the following options:
DateFormat (SimpleDateFormat for custom formats)
Locale-specific format (e.g. day/month/year ordering): Yes
Language-specific names (e.g. English "November" vs. Spanish "Noviembre"): Yes
Does the work for you: Yes. This is the best way and will provide a format that the user is used to working with, with no logic needed on your end.
printf date fields
Locale-specific format: No
Language-specific names: Yes
Does the work for you: Partly (up to you to determine field ordering)
Calendar fields with DateFormatSymbols
Locale-specific format: No
Language-specific names: Yes
Does the work for you: No
Calendar fields with your own string conversions (like a big switch statement):
Locale-specific format: No
Language-specific names: No
Does the work for you: No
Another advantage of DateFormat-based formats vs printf date fields is you can still define your own field ordering and formats with the SimpleDateFormat (just like printf) but you can stick to the DateFormat interface which makes it easier to pass around and combine with stock date formats like DateFormat.getDateInstance(DateFormat.MEDIUM).
Check out the documentation for DateFormat for info on the things you can do with it. Check out the documentation for SimpleDateFormat for info on creating custom date formats. Check out this nice example of date formats (archive) for some example output if you want instant gratification.

There's a direct way how to do it using printf, but it's a pain, too:
String.printf("Time: %1$td-%1$tm %1$tH:%1$tM", new Date());
One problem with it is that it uses 4 formatting strings with the same object, so it needs the 1$ prefix to always access the first argument. The other is that I can never remember what letter means what (but maybe that's just me).
Speed could actually be another problem, if you care.
This is documented in the underlying class Formatter.
My preffered way would be something like
myFormatter.format("Time: [d-m HH:MM]", new Date())
where the braces would save us from repeating $1 and make clear where the argument ends.

Related

Formatting date in Java using SimpleDateFormat

I am trying to parse a date into an appropriate format, but I keep getting the error
Unparseable date
Can anyone tell me what the mistake is?
try {
System.out.println(new SimpleDateFormat("d-MMM-Y").parse("05-03-2018").toString());
} catch (ParseException e) {
e.printStackTrace();
}
I want the date to have this format:
05-Mar-18
Since you want to change the format, first read and parse the date (from String) of your own format in a Date type object. Then use that date object by formatting it into a new (desired) format using a SimpleDateFormat.
The error in your code is with the MMM and Y. MMM is the month in string while your input is a numeric value. Plus the Y in your SimpleDateFormat is an invalid year. yy is what needs to be added.
So here is a code that would fix your problem.
SimpleDateFormat dateFormat = new SimpleDateFormat("d-MM-yyyy");
Date date = dateFormat.parse("05-03-2018");
dateFormat = new SimpleDateFormat("dd-MMM-yy");
System.out.println(dateFormat.format(date));
I hope this is what you're looking for.
There are some concepts about dates you should be aware of.
There's a difference between a date and a text that represents a date.
Example: today's date is March 9th 2018. That date is just a concept, an idea of "a specific point in our calendar system".
The same date, though, can be represented in many formats. It can be "graphical", in the form of a circle around a number in a piece of paper with lots of other numbers in some specific order, or it can be in plain text, such as:
09/03/2018 (day/month/year)
03/09/2018 (monty/day/year)
2018-03-09 (ISO8601 format)
March, 9th 2018
9 de março de 2018 (in Portuguese)
2018年3月5日 (in Japanese)
and so on...
Note that the text representations are different, but all of them represent the same date (the same value).
With that in mind, let's see how Java works with these concepts.
a text is represented by a String. This class contains a sequence of characters, nothing more. These characters can represent anything; in this case, it's a date
a date was initially represented by java.util.Date, and then by java.util.Calendar, but those classes are full of problems and you should avoid them if possible. Today we have a better API for that.
With the java.time API (or the respective backport for versions lower than 8), you have easier and more reliable tools to deal with dates.
In your case, you have a String (a text representing a date) and you want to convert it to another format. You must do it in 2 steps:
convert the String to some date-type (transform the text to numerical day/month/year values) - that's called parsing
convert this date-type value to some format (transform the numerical values to text in a specific format) - that's called formatting
For step 1, you can use a LocalDate, a type that represents a date (day, month and year, without hours and without timezone), because that's what your input is:
String input = "05-03-2018";
DateTimeFormatter inputParser = DateTimeFormatter.ofPattern("dd-MM-yyyy");
// parse the input
LocalDate date = LocalDate.parse(input, inputParser);
That's more reliable than SimpleDateFormat because it solves lots of strange bugs and problems of the old API.
Now that we have our LocalDate object, we can do step 2:
// convert to another format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MMM-yy", Locale.ENGLISH);
String output = date.format(formatter);
Note that I used a java.util.Locale. That's because the output you want has a month name in English, and if you don't specify a locale, it'll use the JVM's default (and who guarantees it'll always be English? it's better to tell the API which language you're using instead of relying on the default configs, because those can be changed anytime, even by other applications running in the same JVM).
And how do I know which letters must be used in DateTimeFormatter? Well, I've just read the javadoc. Many developers ignore the documentation, but we must create the habit to check it, specially the javadoc, that tells you things like the difference between uppercase Y and lowercase y in SimpleDateFormat.

How to present a date that can be parsed by any DateTimeFormatter pattern in Java?

I'm working with a software that uses a lot of DateTimeFormat parsing, in order to minimize the errors, I wonder if I can present the date String in a certain way that it can be parsed by any DateTimeFormat pattern. Ideally it should work as follows:
String date = "...."
DateTimeFormatter format = DateTimeFormat.forPattern(any pattern I want);
DateTime result = format.parseDateTime(date);
Or does the date have to follow the pattern? Thanks for your help
No, you can not get one size fits all. Think if your string is not a legal date at all, something like "hello", how are you going to parse it?
java.time
Java 8 and later includes the java.time framework (Tutorial). The java.time formatter’s pattern may contain []to mark optional parts. This gives you some flexibility. Say you use format:
M[M]['/']['-']['.']d[d]['/']['-']['.']yyyy[' ']['T'][' ']h[h]:mm:ss
So in this case your string may have one or two digits specifying month, day and hour. Month, day and year may be separated by ., - or / and so forth. For example with format above the following strings will be parsed successfully:
1/10/1995 9:34:45
01-10-1995 09:34:45
01.10.1995T09:34:45
…and so forth.
I wrote a utility that has a set of patterns. Once it gets a String it tries to parse it with all the patterns in the set and sees if it succeeds with one of them. If you write such a set of patterns correctly you may ensure that your util supports any possible String that denotes a valid date.
SimpleDateFromat let you set your own date patters. for example dd/mm/yyyy, mm/dd/yyyy, yyyy-mm-dd etc..
This link can give you a better understanding about date patterns and how to use it
use SimpleDateFormat
SimpleDateFormat sdf=new SimpleDateFormat("dd/MM/yyyy");
Date d=sdf.parse("07/12/2014");

Portable way to guarantee that the year field of a DateFormat is only two digits

Currently, I'm having
private ThreadLocal<DateFormat> shortDateFormat = new ThreadLocal<DateFormat>() {
#Override protected DateFormat initialValue() {
final DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
return format;
}
};
Using my Android 4.1, this provides me date in format (In my localization. It may look different for other countries)
19/07/2013
However, sometimes I would like to have a much shorter version like 19/07/13
I do not want to hard code as
dd/MM/yy
As the above way would not portable across different countries. Some countries, their month come before date.
Is there any portable way to achieve so?
p/s Not only month/date order. There might be other problem as well. For instance, China is using 19-07-13 or 19-07-2013. There might be more edge cases for other countries, but I don't know.
SimpleDateFormat dateFormat= (SimpleDateFormat) DateFormat.getDateInstance();
dateFormat.applyPattern(dateFormat.toPattern().replaceAll("y{4}", "yy"));
Explanation:
applyPattern(String pattern) applies the given pattern string to this date format.
dateFormat.toPattern() gets the current pattern
dateFormat.toPattern().replaceAll(String regex, String replacement) returns the current pattern, with regex replaced by replacement.
"y{4}" looks through the date format pattern for a series of 4 y's, and
"yy" says that if you see 4 y's, replace them with 2 instead.
Hope that helped. Good luck.
EDIT:
As MH pointed out, since this is for android, it is probably more appropriate to use:
SimpleDateFormat dateFormat = (SimpleDateFormat)
android.text.format.DateFormat.getDateFormat(getApplicationContext());
This should work fine, since the above method call returns a DateFormat of java.text.DateFormat, not of android.text.format.DateFormat.
You should take a look at the functionality android.text.format.DateFormat provides, on top of the java.text.DateFormat.
In particular, the following method will be of interest:
getDateFormatOrder(Context context)
Javadoc:
Gets the current date format stored as a char array. The array will
contain 3 elements (DATE, MONTH, and YEAR) in the order specified by
the user's format preference. Note that this order is only appropriate
for all-numeric dates; spelled-out (MEDIUM and LONG) dates will
generally contain other punctuation, spaces, or words, not just the
day, month, and year, and not necessarily in the same order returned
here.
In other words, the method allows you to determine what order the day, month and year fields are in, according to the user's preference (which triumphs the user's locale, if you ask me). From there it should easy enough to figure out what 'short' format to use; i.e. dd/MM/yy or MM/dd/yy.
As pointed out by the documentation, the return value of the method is only useful in the context of all-numeric date representations. That should be fine in your case.
If you want portable, rather than using the date object, you could instead create an array with month,date, and year. (I would just use the cal object and access each of the three individually)
Calendar cal = Calendar.getInstance();
int year =cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1;
int day= cal.get(Calendar.DAY);
dateArray[0] = month;
dateArray[1] = year;
dateArray[2] = day;
How about creating a map with localized patterns based on country ISO code and a fallback default pattern in case you don't have a specific country defined?

How do I get localized date pattern string?

It is quite easy to format and parse Java Date (or Calendar) classes using instances of DateFormat.
I could format the current date into a short localized date like this:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String today = formatter.format(new Date());
My problem is that I need to obtain this localized pattern string (something like "MM/dd/yy").
This should be a trivial task, but I just couldn't find the provider.
For SimpleDateFormat, You call toLocalizedPattern()
EDIT:
For Java 8 users:
The Java 8 Date Time API is similar to Joda-time. To gain a localized pattern we can use class
DateTimeFormatter
DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);
Note that when you call toString() on LocalDate, you will get date in format ISO-8601
Note that Date Time API in Java 8 is inspired by Joda Time and most solution can be based on questions related to time.
For those still using Java 7 and older:
You can use something like this:
DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault());
String pattern = ((SimpleDateFormat)formatter).toPattern();
String localPattern = ((SimpleDateFormat)formatter).toLocalizedPattern();
Since the DateFormat returned From getDateInstance() is instance of SimpleDateFormat.
Those two methods should really be in the DateFormat too for this to be less hacky, but they currently are not.
It may be strange, that I am answering my own question, but I believe, I can add something to the picture.
ICU implementation
Obviously, Java 8 gives you a lot, but there is also something else: ICU4J. This is actually the source of Java original implementation of things like Calendar, DateFormat and SimpleDateFormat, to name a few.
Therefore, it should not be a surprise that ICU's SimpleDateFormat also contains methods like toPattern() or toLocalizedPattern(). You can see them in action here:
DateFormat fmt = DateFormat.getPatternInstance(
DateFormat.YEAR_MONTH,
Locale.forLanguageTag("pl-PL"));
if (fmt instanceof SimpleDateFormat) {
SimpleDateFormat sfmt = (SimpleDateFormat) fmt;
String pattern = sfmt.toPattern();
String localizedPattern = sfmt.toLocalizedPattern();
System.out.println(pattern);
System.out.println(localizedPattern);
}
ICU enhancements
This is nothing new, but what I really wanted to point out is this:
DateFormat.getPatternInstance(String pattern, Locale locale);
This is a method that can return a whole bunch of locale specific patterns, such as:
ABBR_QUARTER
QUARTER
YEAR
YEAR_ABBR_QUARTER
YEAR_QUARTER
YEAR_ABBR_MONTH
YEAR_MONTH
YEAR_NUM_MONTH
YEAR_ABBR_MONTH_DAY
YEAR_NUM_MONTH_DAY
YEAR_MONTH_DAY
YEAR_ABBR_MONTH_WEEKDAY_DAY
YEAR_MONTH_WEEKDAY_DAY
YEAR_NUM_MONTH_WEEKDAY_DAY
ABBR_MONTH
MONTH
NUM_MONTH
ABBR_STANDALONE_MONTH
STANDALONE_MONTH
ABBR_MONTH_DAY
MONTH_DAY
NUM_MONTH_DAY
ABBR_MONTH_WEEKDAY_DAY
MONTH_WEEKDAY_DAY
NUM_MONTH_WEEKDAY_DAY
DAY
ABBR_WEEKDAY
WEEKDAY
HOUR
HOUR24
HOUR_MINUTE
HOUR_MINUTE_SECOND
HOUR24_MINUTE
HOUR24_MINUTE_SECOND
HOUR_TZ
HOUR_GENERIC_TZ
HOUR_MINUTE_TZ
HOUR_MINUTE_GENERIC_TZ
MINUTE
MINUTE_SECOND
SECOND
ABBR_UTC_TZ
ABBR_SPECIFIC_TZ
SPECIFIC_TZ
ABBR_GENERIC_TZ
GENERIC_TZ
LOCATION_TZ
Sure, there are quite a few. What is good about them, is that these patterns are actually strings (as in java.lang.String), that is if you use English pattern "MM/d", you'll get locale-specific pattern in return. It might be useful in some corner cases. Usually you would just use DateFormat instance, and won't care about the pattern itself.
Locale-specific pattern vs. localized pattern
The question intention was to get localized, and not the locale-specific pattern. What's the difference?
In theory, toPattern() will give you locale-specific pattern (depending on Locale you used to instantiate (Simple)DateFormat). That is, no matter what target language/country you put, you'll get the pattern composed of symbols like y, M, d, h, H, M, etc.
On the other hand, toLocalizedPattern() should return localized pattern, that is something that is suitable for end users to read and understand. For instance, German middle (default) date pattern would be:
toPattern(): dd.MM.yyyy
toLocalizedPattern(): tt.MM.jjjj (day = Tag, month = Monat, year = Jahr)
The intention of the question was: "how to find the localized pattern that could serve as hint as to what the date/time format is". That is, say we have a date field that user can fill-out using the locale-specific pattern, but I want to display a format hint in the localized form.
Sadly, so far there is no good solution. The ICU I mentioned earlier in this post, partially works. That's because, the data that ICU uses come from CLDR, which is unfortunately partially translated/partially correct. In case of my mother's tongue, at the time of writing, neither patterns, nor their localized forms are correctly translated. And every time I correct them, I got outvoted by other people, who do not necessary live in Poland, nor speak Polish language...
The moral of this story: do not fully rely on CLDR. You still need to have local auditors/linguistic reviewers.
You can use DateTimeFormatterBuilder in Java 8. Following example returns localized date only pattern e.g. "d.M.yyyy".
String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(
FormatStyle.SHORT, null, IsoChronology.INSTANCE,
Locale.GERMANY); // or whatever Locale
The following code will give you the pattern for the locale:
final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern();
System.out.println(pattern1);
Java 8 provides some useful features out of the box for working with and formatting/parsing date and time, including handling locales. Here is a brief introduction.
Basic Patterns
In the simplest case to format/parse a date you would use the following code with a String pattern:
DateTimeFormatter.ofPattern("MM/dd/yyyy")
The standard is then to use this with the date object directly for formatting:
return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy"));
And then using the factory pattern to parse a date:
return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy"));
The pattern itself has a large number of options that will cover the majority of usecases, a full rundown can be found at the javadoc location here.
Locales
Inclusion of a Locale is fairly simple, for the default locale you have the following options that can then be applied to the format/parse options demonstrated above:
DateTimeFormatter.ofLocalizedDate(dateStyle);
The 'dateStyle' above is a FormatStyle option Enum to represent the full, long, medium and short versions of the localized Date when working with the DateTimeFormatter. Using FormatStyle you also have the following options:
DateTimeFormatter.ofLocalizedTime(timeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle);
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle);
The last option allows you to specify a different FormatStyle for the date and the time. If you are not working with the default Locale the return of each of the Localized methods can be adjusted using the .withLocale option e.g
DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH);
Alternatively the ofPattern has an overloaded version to specify the locale too
DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH);
I Need More!
DateTimeFormatter will meet the majority of use cases, however it is built on the DateTimeFormatterBuilder which provides a massive range of options to the user of the builder. Use DateTimeFormatter to start with and if you need these extensive formatting features fall back to the builder.
Please find in the below code which accepts the locale instance and returns the locale specific data format/pattern.
public static String getLocaleDatePattern(Locale locale) {
// Validating if Locale instance is null
if (locale == null || locale.getLanguage() == null) {
return "MM/dd/yyyy";
}
// Fetching the locale specific date pattern
String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance(
DateFormat.SHORT, locale)).toPattern();
// Validating if locale type is having language code for Chinese and country
// code for (Hong Kong) with Date Format as - yy'?'M'?'d'?'
if (locale.toString().equalsIgnoreCase("zh_hk")) {
// Expected application Date Format for Chinese (Hong Kong) locale type
return "yyyy'MM'dd";
}
// Replacing all d|m|y OR Gy with dd|MM|yyyy as per the locale date pattern
localeDatePattern = localeDatePattern.replaceAll("d{1,2}", "dd").replaceAll(
"M{1,2}", "MM").replaceAll("y{1,4}|Gy", "yyyy");
// Replacing all blank spaces in the locale date pattern
localeDatePattern = localeDatePattern.replace(" ", "");
// Validating the date pattern length to remove any extract characters
if (localeDatePattern.length() > 10) {
// Keeping the standard length as expected by the application
localeDatePattern = localeDatePattern.substring(0, 10);
}
return localeDatePattern;
}
Since it's just the locale information you're after, I think what you'll have to do is locate the file which the JVM (OpenJDK or Harmony) actually uses as input to the whole Locale thing and figure out how to parse it. Or just use another source on the web (surely there's a list somewhere). That'll save those poor translators.
You can try something like :
LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy"))
Im not sure about what you want, but...
SimpleDateFormat example:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy");
Date date = sdf.parse("12/31/10");
String str = sdf.format(new Date());

Java Date format

I have a spring web application that runs in Tomcat. I must set the date and number format for my application to a special format.
Can I set the format in any descriptor to the special in my application or I can set the all system format only?
I want to use this pattern: yyyy.mm.dd.
This code is wrong because it's not a standard locale pattern:
String currentDate = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date());
But I don't want type the pattern everywhere in the application, I want set the pattern once.
I want if I type this code:
String currentDate = SimpleDateFormat.getDateInstance(DateFormat.SHORT).format(new Date());
The result is: 2010.08.04.
Is it possible?
java.util.Date objects do not have a format by themselves (they only represent the date and time value, just like integers only represent a number value and don't know anything about formatting numbers).
There is no system-wide default date format setting. When you print a Date object by (implicitly or explicitly) calling toString() on it, it will be printed with a fixed, default format that you can't change:
System.out.println(new Date());
// Example output: Wed Aug 04 09:46:57 CEST 2010
If you want to show a date with a specific format, use a java.text.DateFormat object to format it. For example:
DateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
System.out.println(df.format(new Date()));
// Example output: 04-08-2010 09:48:47
You can absolutely format a date any way you want, no matter if you use Spring or not. First though make sure that you really need a "special formatting", not just a format that is default for a certain locale (like deCH or svSE or enGB) because if you just want to convert a date to your countries native date formatting you can simply use
String currentDate = SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.UK).format(new Date());
And if you really want a custom formatting, you can do like this
String currentDateMyFormat = new SimpleDateFormat("dd:MMM:yy HH.mm").format(new Date());
Of course you can reverse the process (from String to Date) by replacing format with parse.
Hope this answers your question because just like Xu before me, I am not sure I understood your question completely ;)
Since you're talking about doing something application-wide, let me remind you to be cautious with any java.text.Format subclass (including DateFormat, SimpleDateFormat, etc.). As noted in the Javadoc, Formats are generally not thread-safe. I know from personal experience that DateFormats are not.
Therefore, if you're considering setting something up for use across your application, I recommend only defining the format String and sharing it around the application. Instances of a Format class are best-defined in a thread-safe manner, such as on the stack of a method call.

Categories

Resources