Customizing java.text formatters for different Locales - java

Building a java application that supports different Locales, but would like to customize the DateFormat display beyond what is available between FULL, LONG, MEDIUM, and SHORT DateFormat options. Would like to do things like place a character between the date and time components of a DateFormat.getDateTimeFormat(), lowercase the AM/PM, etc, at least for english.
can think of 3 ways to do it:
1) if locale is english, use my custom format string on a new SimpleDateFormat object.
2) modify the default format strings for existing locales
3) create a new locale variant that specifies the format strings I want
Can't figure out how to do 2 or 3 (or if it's even possible), and would rather not do 1... has anyone dealt with anything like this before?
also, seems like 2 or 3 would be necessary for lowercasing the AM/PM ? (Specifiying the AmPmMarkers resource for the locale's dateformat settings)

Why not use a MessageFormat instead?
Use the pattern "{0,date,short} your text here {0,time,short}" to do what you want.

Java has a Class just for this, it is the ResourceBundle Class. Back it with a properties file and you have all that you need plus more.
Even without the ResourceBundle Class you could use properties files to hold all the SimpleDateFormat formats.
Settings formats = new Settings();
Properties SDFFormats = formats.load(propertiesFile);
String SDFAmerica = SDFFormats.getProperty("FormatAmerica");
While the entry into the properties file might read
FormatAmerica = MMM-dd-yyyy

The only thing similar I've dealt with is the fact that "strftime" and "locale" say that Italian should use colons between the time fields, but Java puts full-stops between them. So I've added the following code:
// This is an incredibly ugly hack, but it's based on the fact that
// Java for some reason decided that Italy uses "." between
// hours.minutes.seconds, even though "locale" and strftime say
// something different.
hmsTimeFormat = DateFormat.getTimeInstance(DateFormat.MEDIUM);
if (hmsTimeFormat instanceof SimpleDateFormat)
{
String str = ((SimpleDateFormat)hmsTimeFormat).toPattern();
str = str.replace('.', ':');
hmsTimeFormat = new SimpleDateFormat(str);
}

Most satisfying way to solve this that we've figured out is to load Strings am,pm,formatString from a locale-specific resource bundle, and then:
SimpleDateFormat sdf = (SimpleDateFormat)sdf.getDateTimeInstance(DateTime.SHORT,DateTime.SHORT, locale);
if (formatString != null) {
sdf = new SimpleDateFormat(formatString);
}
if (am!= null && pm != null) {
DateFormatSymbols symbols = sdf.getDateFormatSymbols();
symbols.setAmPmStrings(new String[]{am, pm});
sdf.setDateFormatSymbols(symbols);
}
Paul: not sure there's a separator in the DateFormatSymbols, though... so you probably need to keep the str.replace

I recommend using Joda Time for your date formatting. It is has powerful yet elegant flexibility in its formatting. You'll probably find that its formatters make what you want to do extremely simple.
BTW: once you go Joda you'll never go back!

Related

Default DateTimeFormatter returns empty string when formatting LocalDateTime in Java 8

The following code returns an empty string:
LocalDateTime.parse("2018-01-01T00:00:00.00")
.format(new DateTimeFormatterBuilder().toFormatter())
I'd expect either an exception or the date formatted in some default way.
Have I found a bug in Java or this is as per specification? I cannot find any information in Javadoc about this behaviour.
DateTimeFormatterBuilder is for building a format, it starts off empty. You have to call its various methods such as appendPattern to add the format you want.
DateTimeFormatter has some standard formats you can use straight off. These use DateTimeFormatterBuilder to build the format. For example:
public static final DateTimeFormatter ISO_LOCAL_DATE;
static {
ISO_LOCAL_DATE = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
}
Your code is equivalent to:
LocalDateTime.parse("2018-01-01T00:00:00.00").format(DateTimeFormatter.ofPattern(""))
that produces an empty string in all cases.
I'd expect either exception or the date formatted in some default way
That's your opinion. But IMO, creating an empty builder and add nothing to it should result in a - guess what - "empty" formatter - or a formatter with an empty pattern, or whatever.
The documentation doesn't explicity say this will happen, but it also doesn't say it'll throw an exception or format in some default way. And if the docs don't say that, so why on earth would you expect that? Based on what?
But the worst thing is thinking that, just because your based-on-nothing expectations weren't satisfied, then it's obviously a bug! Why developers - specially the crappy ones - tend to think "wow, I found a bug" when things doesn't go as expected, when most of the time it's their fault?
And why are you creating an empty pattern in the first place?
"OMG, things didn't happen as I expected, so certainly it's a bug!"
-- crappy developer

How do I automatically format all numbers based on the current locale in Android?

I am aware of
NumberFormat nf = NumberFormat.getInstance(Locale.getDefault());
But I want all the numbers shown in my app to be formatted according to the locale, thus I don't think it will be a good way to format them one by one using the above method.
So is there some global setting/variable/configuration that I have to change in order to do that?
Locale-aware formatting requires more than just translating e.g. month names from one language to another. In Java that's handled by separate classes apart from the ones that actually hold the values, e.g. NumberFormat, DateFormat. So there's no way around using them like you already do.
What you could try is to create some wrappers or convenience methods (like formatDate(Date)) to simplify things for you. Also put format strings into Android Resources (res/values).

Java - Duplicate method for taking in a string in a different format

Currently working on a small Java date class program.
Okay, so I have a two constructors which take in dates as either parameters (e.g. 28, 12, 1995), and the other constructor as parsing a string (e.g. "25-4-2009") to find and validate the values. I wish to create another constructor which parses a string but in a different date format which on the surface seems pretty simple to do but I'm not sure as to what logic I should be following.
I have tried creating a new constructor with a different variable for the date string, so instead of "dateString", "dateString2" for instance, however Java doesn't like duplicate methods of the same type.
Should I be creating a new object type, so Date2 and using that to parse the new formatted date string? Or is there a better way to do this?
Thanks.
N.B I am not using SimpleDateFormat, and sorry for the poor title.
No. Do not create another Date2 class. One approach you can take is pass another argument in your constructor something like format. Based on what kind of String you pass in you can use the format argument to distinguish.
Here is a code snippet you can use.
Define an enum of supported formats.
public enum DateFormat {DD_MM_YYYY, MM_DD_YYYY};
Your constructor can look something like:
public MyDate(String date, DateFormat dateFormat) {
switch (dateFormat) {
case DD_MM_YYYY:
// Do some parsing
break;
case MM_DD_YYYY:
// Do some other passing
break;
default:
// Handle invalid format
break;
}
}
Hope it helps :)
As you know, it is impossible to have two constructors with same arguments type. In order to achieve desired, I'd recommend to create a flag (or maybe even enum) to indicate whether format 1 or format 2 is expected:
public ClassName(String date, boolean isDMY) {
if (isDMY) {
//date is like 25-4-2009, do parsing, saving, etc
} else {
//date is in another intended format, for example dd.mm.yyyy, do parsing...
}
}
Note that this solution might be not the best one, but for the cases when you have only two possible formats, and your input is trusted (you're sure that constructor won't be invoked with strings like "20051110", for example), then it's ok IMO.
You said that you aren't using SimpleDateFormat. It sounds like you should (unless this is an assignment that does not allow you to) and have your constructor call a method that can parse and format like so:
public Date(String date) {
this.date = formatDate(String dateStr)
}
here is a great article on parsing dates.
If you cannot write a parsing function that is able to determine the date format from the string dynamically, then you must pass extra information to the constructor signaling which date format it should be expecting by means of a second parameter.
How about using a 2nd parameter for your String constructors?
MyDate(String date, char formatType)
You can use switch afterwards for parsing the date.

Adding a leading zero to a large string in Java

I am currently making an auction program in Java, I am trying to work out deadlines, however my date keeps coming out as (7/04/2013 11:22), is there a way to use String.format to add a leading zero to this date when it is a one digit day?
String timeOne = Server.getDateTime(itemArray.get(1).time).toString()
It causes me a problem later on when I try to sub string it, and it is less than 17 characters long.
Thanks in advance, James.
#Leonard Brünings answer is the right way. And here's why your original code is the wrong way ... even if it worked.
The javadoc for Calendar.toString() says this:
"Return a string representation of this calendar. This method is intended to be used only for debugging purposes, and the format of the returned string may vary between implementations."
Basically you are using toString() for a purpose that the javadoc says you shouldn't. Even if you tweaked the output from toString(), the chances are that your code would be fragile. A change in JVM could break it. A change of locale could break it.
Simply use the SimpleDateFormat
import java.text.SimpleDateFormat;
Calendar timeOne = Server.getDateTime(itemArray.get(1).time)
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm")
System.out.println(sdf.format(timeOne.getTime()))

How to extract time from a string using regex?

The problem is the time displays in different forms,like
19:03
3:29 pm
3:29 PM
How to handle this? thanks
I would recommend using something like SimpleDateFormat for this problem.
What you could do is define your set of dateformats, then parse them in a loop until one format succeeds (i.e. doesn't throw an exception). Something along the lines of the following snippet:
for(SimpleDateFormat fmt : formats) {
try {
return fmt.parse(date, startpos);
} catch(Exception e) {}
}
Naturally this assumes that you created a list of different format patterns. Generally, joda-time is also a good complement to java time.
Unless you write a regex for each possible time format and OR them together, you can't simply do with regex.
What I mean is starting from
(rgx1|rgx2|rgx3)
where rgxX is a valid time regex. In your example you can try
([\d]{1,2}:[\d]{1,2}|[\d]{1,2}:[\d]{1,2} [aApP][mM])
But this regex will also match 45:89 PM which is not a valid time
If you need to extract a time then these are useful, while if you need to verify you can't with regex
I would recommend using Joda's DateTimeFormat. It's guaranteed to be threadsafe, unlike SimpleDateFormat.
DateUtils.parseDate(dateString, patterns[]) from Apache Commons / Lang lets you specify multiple templates that will be tried in turn. Perhaps that's an option if you can identify all possible data formats that will occur.

Categories

Resources