Get one letter abbreviation of week day of a date in java - java

As far I know, in Java I can get weekdays in normal (Friday) or short mode (Fri). But, there is any way to obtain only first letter?
I thought I can get first letter using "substring", but it won't be correct for all languages. For example, spanish weekdays are: Lunes, Martes, Miércoles, Jueves, Viernes, Sábado and Domingo, and first letter for "Miércoles" is X instead of M to difference it from "Martes".

In Android you can use SimpleDateFormat with "EEEEE". In the next example you can see it.
SimpleDateFormat formatLetterDay = new SimpleDateFormat("EEEEE",Locale.getDefault());
String letter = formatLetterDay.format(new Date());
EDIT: it's actually not entirely true. The result on Android could have more than a single letter (and also non-unique, if this matters), but this is what we have. Here's proof that you won't get these characteristics on Android, going over all locales. It's written in Kotlin, but should work for Java too, of course:
val charCountStats = SparseIntArray()
Locale.getAvailableLocales().forEach { locale ->
val sb = StringBuilder("$locale : ")
val formatLetterDay = SimpleDateFormat("EEEEE", locale)
for (day in 1..7) {
val cal = Calendar.getInstance()
cal.set(Calendar.DAY_OF_WEEK, day)
val letter: String = formatLetterDay.format(cal.time)
charCountStats.put(letter.length, charCountStats.get(letter.length, 0)+1)
sb.append(letter)
if (day != 7)
sb.append(',')
}
Log.d("AppLog", "$sb")
}
Log.d("AppLog", "stats:")
charCountStats.forEach { key, value ->
Log.d("AppLog", "formatted days with $key characters:$value")
}
And the result is that for most cases it's indeed a single letter, but for many it's more, and can even reaches 8 characters (though it might look as less letters, even one) :
formatted days with 1 characters:4889
formatted days with 2 characters:471
formatted days with 3 characters:99
formatted days with 4 characters:58
formatted days with 5 characters:3
formatted days with 8 characters:3
Example of a locale that it shows as 3 letters (and not just has 3 letters) is "wo" ("Wolof" language), as this is the result for each of its days of the week using the above formatting:
Dib,Alt,Tal,Àla,Alx,Àjj,Ase

As mentioned above there is no standard Java support for this. Using the formatting string "EEEEE" however is not guaranteed to work on all Android devices. The following code is guaranteed to work on any device:
public String firstLetterOfDayOfTheWeek(Date date) {
Locale locale = Locale.getDefault();
DateFormat weekdayNameFormat = new SimpleDateFormat("EEE", locale);
String weekday = weekdayNameFormat.format(date);
return weekday.charAt(0)+"";
}

There is no standard Java API support for doing that1.
Part of the reason is that many (maybe even most) languages don't have conventional unique one-letter weekday abbreviations. In English there isn't, for example (M T W T F S S).
A (hypothetical) formatting option that doesn't work2 in many / most locales would be an impediment to internationalization rather than a help.
It has been pointed out that:
SimpleDateFormat formatLetterDay =
new SimpleDateFormat("EEEEE", Locale.getDefault());
String letter = formatLetterDay.format(new Date());
gives one letter abbreviations for later versions of Android (18 and above), though the javadocs do not mention this. It appears that this "5 letter" format has been borrowed from DateTimeFormatter whose javadoc says:
The count of pattern letters determines the format.
Text: The text style is determined based on the number of pattern letters used. Less than 4 pattern letters will use the short form. Exactly 4 pattern letters will use the full form. Exactly 5 pattern letters will use the narrow form. ...
If you are targeting Android API 26 or later, you should consider using the java.time.* classes rather than the legacy classes.
But either way, this isn't guaranteed to give you unique day letters.
1 - By "that" I mean mapping to unique 1-letter abbreviations.
2 - I mean it doesn't work in the human sense. You could invent a convention, but typical people wouldn't understand what the abbreviations meant; e.g. they wouldn't know that "X" meant "Miércoles", or in English that (say) "R" meant "Thursday" (see https://stackoverflow.com/a/21049169/139985).

I realize the OP was asking for standards across languages, and this does not address it. But there is/was a standard for using single character Day of Week abbreviation.
Back in mainframe days, using a 1-character abbreviation for Day of Week was common, either to store day of week in 1 character field (to save precious space), or have a report heading for single-character column. The "standard" was to use MTWRFSU, where R was for Thursday, and U for Sunday.
I could not find any definitive references to this (which is why I quoted "standard", but here are a couple of examples:
http://eventguide.com/topics/one_digit_day_abbreviations.html
http://www.registrar.ucla.edu/soc/definitions.htm#Anchor-Days-3800

I think there's no direct java function to get the first letter and no standard way to do it.
You can refer to this link to obtain the first letter of the string day using substring() java method
Given a string in Java, just take the first X letters

DateFormatSymbols.getWeekdays with a width of NARROW will give you the first letter of each week day. It works for every language. However, it requires API 24.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String[] weekDays = DateFormatSymbols.getInstance(Locale.getDefault())
.getWeekdays(DateFormatSymbols.STANDALONE, DateFormatSymbols.NARROW);
}

Related

NL locale returns ambiguous number

if I want to use different number formats across Europe to one format (double), it doesn't seem to work.
Locale locale = new Locale("nl", "NL");
NumberFormat nf= NumberFormat.getNumberInstance(locale);
returns nf.parse("4,000.00").doubleValue();
it returns 4.000 instead of 4000.0, but when enter nf.parse("900,00") it works (returns 900.0)
Another time I enter 4000 and it converts to 4000.0 (expected).
So now I am left with inconsistent types.
I want to convert each number to the same double format. can you guide me?
now I am left with inconsistent types
This is incorrect. The behaviour is entirely consistent and according to spec.
In dutch, the comma is the wholes/fractions separator: There can be only one, and everything to the left is the wholes, and to the right of it, the fractional part. The dot is the thousands separator.
900,00
This is parsed as nine hundred, whole. 900 is to the left of the comma - so those are the wholes. 00 is the fractional part, which is nothing, so, you end up with 900. As expected - a dutch person reading 900,00 would assume that said 'nine hundred'.
4000
Obviously, that's four thousand. No problems there.
4,000.00
That's 4,000 - i.e. four, with 000 as fractional part, and that is how this is parsed. The .00 isn't parsed at all.
Wait, what?
NumberFormat is designed to parse multiple numbers from a stream of text. Even the .parse(string) version of it. Here, try it:
Locale locale = new Locale("nl", "NL");
NumberFormat nf= NumberFormat.getNumberInstance(locale);
System.out.println(nf.parse("4,000hey now this is strange").doubleValue();
works and runs fine, and prints '4'.
Fixing it
If you really want to fix it, you have a few strategies. One of them, is to first verify that the entire input is valid (e.g. with a regular expression) and only then parsing it.
Another option is to explicitly check that the whole input is consumed. You can do that:
String input = "4,000.00";
ParsePosition ps = new ParsePosition(0);
Locale locale = new Locale("nl", "NL");
NumberFormat nf = NumberFormat.getNumberInstance(locale);
double v = nf.parse(input, ps).doubleValue();
if (ps.getIndex() != input.length()) throw new IllegalArgumentException("Not a number: " + input);
The above code parses 900,00 as nine hundred, parser 4000 as four thousand, same for 4.000, and throws an exception if you attempt to toss 4,000.00 at it. Which is, indeed, not a valid anything in dutch locale.
I want something that parses both 4,000.00 as 4000, but also 900,00 as 900.
That is highly inconsistent and implies you want 4,000 to be parsed as 4 and yet 4,000.00 as 4000. If you want this, you're on your own and have to write it from scratch, no built in library (or, as far as I know, any external one) would do such utter befuddled inconsistent craziness.
NB: Note that the snippet would parse 4.000.00 as 400000 and works fine; inconsistent application of thousands separators is leniently parsed by NumberFormat and you can't tell it to be strict. In fact, 4.1.23.4567 is parsed as 41234567 - the only reason 4,000.00 is not parsed in the first place is because dots are not allowed in the fractional part at all. If you don't want that, you're again stuck, you can't use NumberFormat then. Regexes maybe, but you're now on the hook for writing one for each locale you care to support.

How to set the currency symbol to the correct locale position ($ 20 vs 20 $) - Joda money

I am using this bit of code to format my currencies (I am using joda money)
public static MoneyFormatter getDefaultLocaleFormatter() {
return new MoneyFormatterBuilder()
.appendAmountLocalized()
.appendLiteral(" ")
.appendCurrencySymbolLocalized()
.toFormatter().withLocale(Locale.getDefault());
}
But as you can see, the currency symbol comes always after the amount. What I want is the correct positioning according to the given locale. Example:
Some countries may use: 20 $, others might use $20. Some might have a space in between others don't.
I did not find the solution within the library altough it seems that it should support that (It supports localizing all the rest)

JavaScript formatting time 24hours format to 12hours

I was having some trouble when trying to format time in 24 hours format to 12 hours format. Here are some of the example of my time in string format:
0:00, 9:00, 12:00, 15:00
I wonder how should I substr the first two character in JavaScript because some of them were one digit and some were two. The output time format should be in 12 hours format like:
12:00AM, 9:00AM, 12:00PM, 3:00PM
Any guides? Thanks in advance.
In comments you clarified that each string you process will have only a single time in it (i.e., you are not processing a single string with four comma-separated times in it). So essentially you have input as follows:
var input = "9:00";
The easiest way to extract the hour and minute is using the String .split() method. This splits up the string at a specified character - in your case you'd use ":" - and returns an array with the pieces:
var parts = input.split(":"),
hour = parts[0],
minute = parts[1];
The obvious answer would be to use regular expressions (but remember AWZ's rule: if you have a problem and decide it can be solved with RE's, then you now have two prolems).
However, save yourself a whole helluva lot of trouble and get moment.js

java regex match up to a string

Regex'ers:
How can I construct a Java Regex to match Strings lexigraphically <= to a given date string?
For example, suppose the input is in YYYY-DD-MM format:
2014-01-20 MLK day
2007-04-14 'twas a very good day
2014-05-19 is today
1998-11-30 someone's birthday
I'd like the filter to return all lines before, say, Groundhog's day of this year, 2014-02-20;
so in the above list the regex would return all lines except today. (I don't want to convert the
dates to Epoch time; I'd like to just pass a Regex to a class that runs a map/reduce job so that
my input record reader can use the Regex as it constructs bundles to deliver to the mappers.)
TIA,
It's near impossible to do <= type logic with regular expressions. You technically could, but you'd have to map out every possible scenario...and then if you want to change the date you are comparing to, the whole expression would change. Instead, I'd just match all the dates/values and then use a date parser to see if it less then the date. Here's an expression to get you started:
(\d{4}-\d{2}-\d{2})\s+(.*)
Then the date will be in capture group one. If it is <= Groundhog's day, then you have the value in capture group two.
To show how complicated it is to do <= logic with regular expression, I whipped together a quick expression to match numbers > 0 and <= 27.
^([1-9]|1[0-9]|2[0-7])$
As you can see, we pretty much need to map out each scenario. You can imagine how much more of a headache this would be with a date..and you wouldn't just be able to say "2014-02-02", you'd need to redo the majority of the expression.

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