Adding a leading zero to a large string in Java - 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()))

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

Java SimpleDateFormat adds random zeroes

I have an Android app that outputs a csv with several hundred lines per second. Each line has a timestamp that is basically generated like this:
String formatTimeStamp (Calendar cal)
{
SimpleDateFormat timeFormatISO = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
return timeFormatISO.format(cal.getTime());
}
Some timestamps (maybe one in a thousand) have unexpected zeroes in them and look something like this:
2016-04-12T09:0011:30
2016-04-12T0009:0011:30
2016-04-0012T09:11:30
The occurrences seem completely arbitrary, at least
I don't see any pattern behind them. Sometimes there are several thousand lines between two wrong lines, sometimes there is just one.
The date format is defined in only one place in the code.
Edit:
Here
are the faulty timestamps of my last run, just so you can take a look at it. The only thing I have noted about them is that it's always two leading zeroes in front of a date element, never in front of the year, though.
Edit 2:
Issue resolved! Turns out SimpleDateFormat is not thread safe and does weird things to strings if used incorrectly. I didn't know multithreading would be an issue, so I didn't point it out in the initial question. Sorry about the confusion.
"Turns out SimpleDateFormat is not thread safe and does weird things to strings if used incorrectly."
The code you showed us in your Question is thread-safe unless the value of cal is being handled in a non-safe way.
The SimpleDateFormat instance is thread-confine; i.e. no other threads can see it. Therefore, its thread-safety or otherwise is not relevant.
My guess is that in your actual code you had multiple threads attempting to share a SimpleDateFormat instance. The javadoc says:
"It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally."
you need to specify the timezone in the input string.
for example :
timeFormatISO.setTimeZone(TimeZone.getTimeZone("GMT"));

Understanding the strange output of java.util.Locale

I had a perception that Locale is just about adding comma at proper positions at least in case of numbers. But I see a different output for what I have tried.
I tried the following,
public static void main(String[] args) {
DecimalFormat df = null;
df = (DecimalFormat) DecimalFormat.getInstance(Locale.CHINESE);
System.out.println("Locale.CHINESE "+df.format(12345.45));
df = (DecimalFormat) DecimalFormat.getInstance(Locale.GERMAN);
System.out.println("Locale.GERMAN "+df.format(12345.45));
}
Output:
Locale.CHINESE 12,345.45
Locale.GERMAN 12.345,45
If you carefully look at the comma's, you'll see a major difference.
Now, the javadoc for java.util.Locale says
... An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to
tailor information for the user. For example, displaying a number is a locale-sensitive operation--the number
should be formatted according to
the customs/conventions of the user's native country, region, or culture ...
I see a comma being interpreted as decimal point in another Locale, which is really a curious thing, as the value is being changed.
So, help me understand this. What exactly is Locale? Won't the drastic change in output cause major issue in code/data?
I had a perception that Locale is just about adding comma at proper positions at least in case of numbers.
No, it affects the symbols used as well, as you've seen.
So, help me understand this. What exactly is Locale? Won't the drastic change in output cause major issue in code/data?
Only if you don't use them correctly :) Machine-to-machine communication should usually not be localized; typically if you really need to use text, it's best to use US as a reasonably invariant locale.
See DecimalFormatSymbols for more details of what is locale-specific.
I see nothing wrong with the above. The German way of representing 12345.45 is 12.345,45
and the Chinese way of representing the same number is 12,345.45 .
So, help me understand this. What exactly is Locale? Won't the drastic
change in output cause major issue in code/data?
No it won't you just need to keep track of the locale of the input and how you want it formatted.

Parsing Ambiguous Dates in Java

Is there any way in Java to guess the date format when it is not explicitly defined?
For example a user types in 11Mar09 or 11-09-2009 or 11/09/2009 or 11-09 what is the best way of parsing this to a Date object without either a bunch of try catch or raising an error?
I don't think you want to do this, especially based on your examples, but if you must, I think your best bet will be to use something like Apache's DateUtils in commons-lang:
String[] datePatterns = new String[] {
"ddMMMyy", // ex. 11Mar09
"dd-MM-yyyy", // ex. 11-09-2009
"dd/MM/yyyy", // ex. 11/09/2009
"dd-MM" // ex. 11-09
}
Date date = DateUtils.parseDate(stringDate, datePatterns);
Unfortunately dates like the fourth one above will be problematic - is "11/09" September 11th, November 9th, September 2011, November 2009, or something else?
My recommendation is don't. Use a date picker or an explicitely noted format. Guessing will lead to all kinds of problems, easily including, if the date is a critical one, litigation.
If you have to guess, provide some form of feedback that is non-ambiguous, something like a confirmation page that says "Your flight will be booked on the 9th of November, 2009. Is this correct?".
You could have a bunch of regular expressions and cycle through until you find a match. I think you could also have a bunch of DateFormats and cycle through them, catching exceptions on ones that failed.
The first avoids using exceptions for non-exceptional cases, the second is maybe better from a design point of view in that you're using a date parsing framework for what it was designed for. But overall, I don't think either approach is necessarily "best" or "worst" per se-- more a matter of personal preferences/beliefs.
As the domain of possible date-strings are infinite, I don't see how it could be possible to recognize them all. You can however pick a subset for pattern-matching.
You give no clues about your user-interface, but the best approach here would be to help the user input the date. For example with a pop-up calendar or just forcing a predefined format.

Customizing java.text formatters for different Locales

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!

Categories

Resources