Is there an equivalent to php date() style formatting in Java? I mean, in php I can backslash-escape characters to have them treated literally. I.e. yyyy \y\e\a\r would become 2010 year. I did not find anything similar in Java, all examples deal only with built-in date formats.
In particular, I deal with JCalendar date pickers and their dateFormatString property.
I need it because in my locale it is required to write all sorts of additional stuff in date format, like d. (for day) after days part, m. (for years) after years part and so on.
At the worst case I could use string replace or regexp but maybe there's a simpler way?
Sure, with the SimpleDateFormat you can include literal strings:
Within date and time pattern strings, unquoted letters from 'A' to 'Z' and from 'a' to 'z' are interpreted as pattern letters representing the components of a date or time string. Text can be quoted using single quotes (') to avoid interpretation. "''" represents a single quote. All other characters are not interpreted; they're simply copied into the output string during formatting or matched against the input string during parsing.
"hh 'o''clock' a, zzzz" 12 o'clock PM, Pacific Daylight Time
Just for completeness, Java 8's DateTimeFormatter also supports this:
DateTimeFormatter.ofPattern("yyyy 'year'");
java.time
Mark Jeronimus said it already. I am fleshing it out a bit more. Just put the text to be printed literally inside single quotes.
DateTimeFormatter yearFormatter = DateTimeFormatter.ofPattern("yyyy 'year'");
System.out.println(LocalDate.of(2010, Month.FEBRUARY, 3).format(yearFormatter));
System.out.println(Year.of(2010).format(yearFormatter));
System.out.println(ZonedDateTime.now(ZoneId.of("Europe/Vilnius")).format(yearFormatter));
Output when running just now:
2010 year
2010 year
2019 year
If you are using a DateTimeFormatterBuilder and its appendPattern method, use single quotes in the same way. Or use its appendLiteral method instead and no single quotes.
How do we put a single quote in the format, then? Two single quotes produce one. It doesn’t matter if the double single quote is inside single quotes or not:
DateTimeFormatter formatterWithSingleQuote = DateTimeFormatter.ofPattern("H mm'' ss\"");
System.out.println(LocalTime.now(ZoneId.of("Europe/London")).format(formatterWithSingleQuote));
10 28' 34"
DateTimeFormatter formatterWithSingleQuoteInsideSingleQuotes
= DateTimeFormatter.ofPattern("hh 'o''clock' a, zzzz", Locale.ENGLISH);
System.out.println(ZonedDateTime.now(ZoneId.of("America/Los_Angeles"))
.format(formatterWithSingleQuoteInsideSingleQuotes));
02 o'clock AM, Pacific Daylight Time
All of the formatters above can be used for parsing too. For example:
LocalTime time = LocalTime.parse("16 43' 56\"", formatterWithSingleQuote);
System.out.println(time);
16:43:56
The SimpleDateFormat class used when this question was asked nearly 10 years ago is notoriously troublesome and long outdated. I recommend that instead you use java.time, the modern Java date and time API. Which is why I demonstrate just that.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Documentation of DateTimeFormatter
You can use String.format as documented in java.util.Formatter:
Calendar c = ...;
String s = String.format("%tY year", c);
// -> s == "2010 year" or whatever the year actually is
java.text.SimpleDateFormat
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String formattedDate = formatter.format(date);
You'll get more info here link text
Related
Is there a way to format a day and month (in compact form), but not year, in the locale-correct order in Java/Kotlin? So for English it should be "Sep 20" but for Swedish "20 sep.".
For comparison, on Cocoa platforms, I can do the following (in Swift):
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "sv_SE")
formatter.setLocalizedDateFormatFromTemplate("MMM d")
print(formatter.string(from: Date()))
This will correctly turn things around. Is there an equivalent thing to do with the Java SDKs? I've been trying various forms with both DateTimeFormatter and the older SimpleTimeFormat APIs, but no success.
Notes: Unlike this question, I don't want the full medium format that includes the year. I also don't want either DateTimeFormatter.ofPattern("MMM d"), since that gives the incorrect result in Swedish, or DateTimeFormatter.ofPattern("d MMM"), since that gives the incorrect result in English.
No, sorry. I know of no Java library that will automatically turn "MMM d" around into 20 sep. for a locale that prefers the day of month before the month abbreviation.
You may try modifying the answer by Rowi in this way:
DateTimeFormatter ft =
DateTimeFormatter
.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.forLanguageTag("sv-SE"))
;
However the result is:
20 sep. 2019
It includes the year, which you didn’t ask for.
An advanced solution would use the DateTimeFormatterBuilder class to build DateTimeFormatter objects.
DateTimeFormatterBuilder
.getLocalizedDateTimePattern(
FormatStyle.MEDIUM,
null,
IsoChronology.INSTANCE,
Locale.forLanguageTag("sv-SE")
)
This returns d MMM y. Modify this string to delete the y and the space before it. Note that in other languages the y may be yy, yyyy or u and may not come last in the string. Pass your modified format pattern string to DateTimeFormatter.ofPattern.
It may be shaky. Even if you look through the format pattern strings for all available locales, the next version of CLDR (where the strings come from) might still contain a surprise. But I think it’s the best we can do. If it were me, I’d consider throwing an exception in case I can detect that the string from getLocalizedDateTimePattern doesn’t look like one I know how to modify.
You can do it in Java using LocalDate:
LocalDate dt = LocalDate.parse("2019-09-20");
System.out.println(dt);
DateTimeFormatter ft = DateTimeFormatter.ofPattern("dd MMM", new Locale("sv","SE"));
System.out.println(ft.format(dt));
You could get the DateFormat's pattern and remove the year:
val locale: Locale
val datePattern = (DateFormat.getDateInstance(DateFormat.MEDIUM, locale) as SimpleDateFormat).toPattern()
.replace("y", "").trim { it < 'A' || it > 'z' }
I am trying to parse following date time string
2018-01-30T23:59:59.000
I am not able to understand which standard format it is like UTC or ISO_8601
while parsing in the following manner:
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD'T'HH:MM:SS:MS");
Date date = null;
try {
date = sdf.parse("2018-01-30T23:59:59.000");
} catch (ParseException e) {
e.printStackTrace();
}
But It is throwing following exception:
java.text.ParseException: Unparseable date: "2018-01-30T23:59:59.000"
Any help is appreciated.
See the doc of SimpleDateFormat and try this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime dateTime = LocalDateTime.parse("2018-01-30T23:59:59.000");
System.out.println(dateTime);
This prints:
2018-01-30T23:59:59
Your string is in ISO 8601 format. UTC or Coordinated Universal Time is not a format, it is a standard time used to define the time the rest of use in our respective time zones.
The date-time classes you were using, SimpleDateFormat and Date, are long outdated and the former in particular notoriously troublesome. I recommend that you instead use java.time, the modern Java date and time API. It is so much nicer to work with.
A LocalDateTime is a date with time of day and without time zone or offset from UTC. Its one-argument parse method parses ISO 8601, which is why no explicit formatter is needed.
What went wrong in your code
Your format pattern string has a number of issues to it. Which is one reason why you should appreciate the above solution without any explicit formatter. The first thing that goes wrong is: Your format pattern string has a colon, :, between seconds and milliseconds, whereas your date-time string has a dot, .. This is why you get the exception.
However, fixing this, your code yields the following Date:
Sun Dec 31 23:00:00 CET 2017
It’s one month off from the expected, and the minutes and seconds are missing. Because:
Uppercase YYYY is for week-based year and only useful with a week number. You need lowercase yyyy for year.
Uppercase DD is for day of year. You need lowercase dd for day of month.
You correctly used uppercase MM for month. Trying the same again for minutes won’t work. Maybe you can guess by now: it’s lowercase mm.
Not surprising you need lowercase ss for seconds.
UsingMS for milliseconds is interesting. SimpleDateFormat takes it as M for month (which we’ve already had twice before) and uppercase S for millisecond. Instead you needed uppercase SSS for the three digits of milliseconds.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
Wikipedia article: Coordinated Universal Time on UTC
You need to escape the literal T:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:SS");
See This SO Answer for more examples
Update: Your string is in the format
yyyy-MM-dd'T'HH:mm:ss.SSS
but you are trying to parse it with a completely uppercase format string.
This does not do what you want it to do and you should read the documentation on SimpleDateFormat and the format string placeholders
Actually, I found problem with MM/dd/yy date format :
If enter year greater than 37 then the year format reflects as 1937.
i.e, if I enter input as 02/05/37 then when I am printing this date into console the date changes into 02/05/1937.
if he entered less than 02/05/37 then working fine.
Date startDate = new SimpleDateFormat("dd/MM/yy").parse("01/01/47");
System.out.println(startDate);
Assuming you're using SimpleDateFormat: It's conform specifications that 02/05/37 is parsed as 02/05/1937. At least for the next year or so...
Java's SimpleDateFormat has to decide in which century your date should be. It does this by adjusting dates to be within 80 years before and 20 years after the time the SimpleDateFormat instance is created. 2037 is within 80 years before the current date (2016), so it uses a time in the past.
The other answers are correct. You need to understand SimpleDateFormat behavior for assuming your intended century.
You are using old outmoded classes. The new recommended classes have a different behavior on this issue.
java.time
The java.time framework built into Java 8 and later supplants the old java.util.Date & SimpleDateFormat classes.
The behavior about assuming century is different. In the DateTimeFormatter class, a two-digit century is interpreted as being in the 21st century, resulting in a year within the range 2000 to 2099 inclusive.
The java.time classes include LocalDate for representing a date-only value without time-of-day and without time zone.
String input = "02/01/47";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd/MM/yy" );
LocalDate localDate = LocalDate.parse( input , formatter );
2047-01-02
By the way, a tip: Avoid two-digit years if at all possible. The confusion and trouble induced is not worth the savings of two bytes and a smudge of toner.
If you don't supply century info, then it has to make an assumption and it quite reasonably assumes that you are going to want mostly dates in the past, with some scope for future dates, but not too far, as it's more likely that you'll want prior dates, such as birth dates, etc. And people quite commonly live up to about 80 years of age. So far more dates will be in the past for any given current date, than future ones, based on this assumption.
From the spec...
For parsing with the abbreviated year pattern ("y" or "yy"),
SimpleDateFormat must interpret the abbreviated year relative to some
century. It does this by adjusting dates to be within 80 years before
and 20 years after the time the SimpleDateFormat instance is created.
For example, using a pattern of "MM/dd/yy" and a SimpleDateFormat
instance created on Jan 1, 1997, the string "01/11/12" would be
interpreted as Jan 11, 2012 while the string "05/04/64" would be
interpreted as May 4, 1964. During parsing, only strings consisting of
exactly two digits, as defined by Character.isDigit(char), will be
parsed into the default century. Any other numeric string, such as a
one digit string, a three or more digit string, or a two digit string
that isn't all digits (for example, "-1"), is interpreted literally.
So "01/02/3" or "01/02/003" are parsed, using the same pattern, as Jan
2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
Otherwise, calendar system specific forms are applied. For both
formatting and parsing, if the number of pattern letters is 4 or more,
a calendar specific long form is used. Otherwise, a calendar specific
short or abbreviated form is used.
So, if you to do something with this, then you'll need to check if the formatted date is prior to today's date (or some other cut off that you choose) and just add 100 years to the given date, if you wish to only have future dates or beyond a different cut off from the default one.
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");
Is there a simple way to parse a date that may be in MM/DD/yyyy, or M/D/yyyy, or some combination? i.e. the zero is optional before a single digit day or month.
To do it manually, one could use:
String[] dateFields = dateString.split("/");
int month = Integer.parseInt(dateFields[0]);
int day = Integer.parseInt(dateFields[1]);
int year = Integer.parseInt(dateFields[2]);
And validate with:
dateString.matches("\\d\\d?/\\d\\d?/\\d\\d\\d\\d")
Is there a call to SimpleDateFormat or JodaTime that would handle this?
Yep, use setLenient:
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
df.setLenient(true);
System.out.println(df.parse("05/05/1999"));
System.out.println(df.parse("5/5/1999"));
java.time
Java 8 and later includes the java.time framework. This framework obsoletes the old java.util.Date/.Calendar classes discussed in the other answers here.
The java.time.format package and its java.time.format.DateTimeFormatter class use pattern codes similar to that seen in the accepted Answer by Ray Myers. While similar, they vary a bit. In particular they are strict about the number of repeated characters. If you say MM, then the month must have padded zero or else you get a DateTimeParseException. If the month number may or may not have a padding zero, simply use the single-character M.
In this example code, note how the month number of the input string has a padding zero while the day-of-month number does not. Both are handled by the single-character pattern.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "M/d/yyyy" );
LocalDate localDate = formatter.parse ( "01/2/2015" , LocalDate :: from );
Dump to console.
System.out.println ( "localDate: " + localDate );
localDate: 2015-01-02
Looks like my problem was using "MM/DD/yyyy" when I should have used "MM/dd/yyyy". Uppercase D is "Day in year", while lowercase d is "Day in month".
new SimpleDateFormat("MM/dd/yyyy").parse(dateString);
Does the job. Also, "M/d/y" works interchangeably. A closer reading of the SimpleDateFormat API Docs reveals the following:
"For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields."