Android - SimpleDateFormat IllegalArgumentException: Unknown pattern character 'u' - java

Logcat:
FATAL EXCEPTION: main
java.lang.IllegalArgumentException: Unknown pattern character 'u'
Here is my Code:
long ticket = 1473808310826L;
SimpleDateFormat sdf = new SimpleDateFormat("u");
String test = sdf.format(ticket);
Using: JDK 8
u is used in the documentation of SimpleDateFormat:
Day number of week (1 = Monday, ..., 7 = Sunday)

The documentation of SimpleDateFormat is misleading (as of 09/16/2016, for future readers).
There is no u pattern character in Android.
From the source code of SimpleDateFormat:
static final String PATTERN_CHARS = "GyMdkHmsSEDFwWahKzZLc";
// ...
private void validatePatternCharacter(char format) {
int index = PATTERN_CHARS.indexOf(format);
if (index == -1) {
throw new IllegalArgumentException("Unknown pattern character '"
+ format + "'");
}
}
To get the current day of the week, you could do something like this:
Calendar calendar = Calendar.getInstance();
// if you do not wish to use the current time, but a specific one
// calendar.setTimeInMillis(yourTimeInMillis);
switch (calendar.get(Calendar.DAY_OF_WEEK)) {
case Calendar.MONDAY:
// monday
break;
case Calendar.TUESDAY:
// tuesday
break;
// ...
}

Related

Java parse date from string including -th day of month [duplicate]

I checked the SimpleDateFormat javadoc, but I am not able to find a way to parse the ordinal indicator in a date format like this:
Feb 13th 2015 9:00AM
I tried "MMM dd yyyy hh:mma", but the days have to be in number for it to be correct?
Is it possible to parse the "13th" date using a SimpleDateFormat without having to truncate the string?
Java's SimpleDateFormat doesn't support an ordinal suffix, but the ordinal suffix is just eye candy - it is redundant and can easily be removed to allow a straightforward parse:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\\d)(st|nd|rd|th)", ""));
The replace regex is so simple because those sequences won't appear anywhere else in a valid date.
To handle any language that appends any length of ordinal indicator characters from any language as a suffix:
Date date = new SimpleDateFormat("MMM dd yyyy hh:mma")
.parse(str.replaceAll("(?<=\\d)(?=\\D* \\d+ )\\p{L}+", ""));
Some languages, eg Mandarin, prepend their ordinal indicator, but that could be handled too using an alternation - left as an exercise for the reader :)
Java 8 answer (and Java 6 and 7) (because when this question was asked in 2015, the replacement for SimpleDateFormat was already out):
DateTimeFormatter parseFormatter = DateTimeFormatter
.ofPattern("MMM d['st']['nd']['rd']['th'] uuuu h:mma", Locale.ENGLISH);
LocalDateTime dateTime = LocalDateTime.parse(dateTimeString, parseFormatter);
With the sample date from the question this yiedls:
2015-02-13T09:00
In the format pattern [] denotes optional parts and '' denotes literal parts. So the pattern says that the number may be followed by st, nd, rd or th.
To use this in Java 6 or 7 you need ThreeTen Backport. Or for Android ThreeTenABP.
Since those suffixes are special for English, and other languages/locales have completely other usages for writing dates and times (also they don’t use AM/PM), I believe that unless you have other requirements, you should try to implement this for English dates and times only. Also you should give an English speaking locale explicitly so it will work independently of the locale setting of your computer or JVM.
I have tried to combine the best parts of answers by Hugo and myself to a duplicate question. Under that duplicate question there are still more java 8 answers. One limitation of the above code is it doesn’t have very strict validation: you will get away with Feb 13rd and even Feb 13stndrdth.
Edit: My own favourite among my answers on ordinal indicators is this one. It’s about formatting, but the formatter I present there works fine for parsing too.
In case someone finds it useful: DateTimeFormatter builder. This formatter allows you to format and to parse UK dates with ordinal suffixes (eg. "1st January 2017"):
public class UkDateFormatterBuilder
{
/**
* The UK date formatter that formats a date without an offset, such as '14th September 2020' or '1st January 2017'.
* #return an immutable formatter which uses the {#link ResolverStyle#SMART SMART} resolver style. It has no override chronology or zone.
*/
public DateTimeFormatter build()
{
return new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.parseLenient()
.appendText(DAY_OF_MONTH, dayOfMonthMapping())
.appendLiteral(' ')
.appendText(MONTH_OF_YEAR, monthOfYearMapping())
.appendLiteral(' ')
.appendValue(YEAR, 4)
.toFormatter(Locale.UK);
}
private Map<Long, String> monthOfYearMapping()
{
Map<Long, String> monthOfYearMapping = new HashMap<>();
monthOfYearMapping.put(1L, "January");
monthOfYearMapping.put(2L, "February");
monthOfYearMapping.put(3L, "March");
monthOfYearMapping.put(4L, "April");
monthOfYearMapping.put(5L, "May");
monthOfYearMapping.put(6L, "June");
monthOfYearMapping.put(7L, "July");
monthOfYearMapping.put(8L, "August");
monthOfYearMapping.put(9L, "September");
monthOfYearMapping.put(10L, "October");
monthOfYearMapping.put(11L, "November");
monthOfYearMapping.put(12L, "December");
return monthOfYearMapping;
}
private Map<Long, String> dayOfMonthMapping()
{
Map<Long, String> suffixes = new HashMap<>();
for (int day=1; day<=31; day++)
{
suffixes.put((long)day, String.format("%s%s", (long) day, dayOfMonthSuffix(day)));
}
return suffixes;
}
private String dayOfMonthSuffix(final int day)
{
Preconditions.checkArgument(day >= 1 && day <= 31, "Illegal day of month: " + day);
if (day >= 11 && day <= 13)
{
return "th";
}
switch (day % 10)
{
case 1: return "st";
case 2: return "nd";
case 3: return "rd";
default: return "th";
}
}
}
Plus a fragment of the test class:
public class UkDateFormatterBuilderTest
{
DateTimeFormatter formatter = new UkDateFormatterBuilder().build();
#Test
public void shouldFormat1stJanuaryDate()
{
final LocalDate date = LocalDate.of(2017, 1, 1);
final String formattedDate = date.format(formatter);
Assert.assertEquals("1st January 2017", formattedDate);
}
#Test
public void shouldParse1stJanuaryDate()
{
final String formattedDate = "1st January 2017";
final LocalDate parsedDate = LocalDate.parse(formattedDate, formatter);
Assert.assertEquals(LocalDate.of(2017, 1, 1), parsedDate);
}
}
PS. I used Greg Mattes' solution for ordinal suffixes from here:
How do you format the day of the month to say "11th", "21st" or "23rd" in Java? (ordinal indicator)
Well, no need to replace the text. The DateTimeFormatterBuilder is able to parse this as well.
First, we need to create a Map which maps day-of-month against their day-of-month-with-ordinal-suffix. That is because unfortunately, there is no standard thing, as far as I know.
static final Map<Long, String> ORDINAL_SUFFIX_MAP;
static {
Map<Long, String> map = new HashMap<>();
for (int i = 1; i <= 31; i++) {
String suffix = switch (i) {
case 1, 21, 31 -> "st";
case 2, 22 -> "nd";
case 3, 23 -> "rd";
default -> "th";
};
map.put((long) i, i + suffix);
}
ORDINAL_SUFFIX_MAP = Map.copyOf(map);
}
Then we can utilize the DateTimeFormatterBuilder as follows:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern(firstPartOfYourPattern)
.appendText(ChronoField.DAY_OF_MONTH, ORDINAL_SUFFIX_MAP)
.appendPattern(lastPartOfYourPattern)
.toFormatter(Locale.ROOT);
LocalDateTime result = LocalDateTime.parse(str, formatter);
You should be using RuleBasedNumberFormat. It works perfectly and it's respectful of the Locale.

Android date format with Month [duplicate]

This question already has answers here:
How do I convert the date from one format to another date object in another format without using any deprecated classes?
(10 answers)
Closed 1 year ago.
How to get the Android date format "7/25/2021" to July/25/2021
Here is the portion of the code
mDisplayDate is the Textview
mDisplayDate.setOnClickListener(view -> { Calendar cal = Calendar.getInstance();
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int day = cal.get(Calendar.DAY_OF_MONTH);
String dateLong = month + "/" + day+ "/" + year;
mDisplayDate.setText(dateLong);
The easiest way to do this is to use a switch case
String monthStr = "";
switch(month) {
case 1:
monthStr = "January";
break;
case 2:
monthStr = "February";
break;
// and else
}
String dateLong = monthStr + "/" + day+ "/" + year;
You could use the android documentation link, that I shared in the comments to learn about SimpleDateFormat.
The Pattern to be used should be MMMM/dd/yyyy
MMMM - gives month name
dd - gives the days of the month
yyyy - gives the year
Date date = Calendar.getInstance().getTime();
DateFormat formatter = new SimpleDateFormat("MMMM/dd/yyyy");
String today = formatter.format(date);
mDisplayDate.setText(today);
Note: You may use MMM for month names in 3 letters only.
Read more about patterns here.

Convert from Gregorian to Julian calendar [duplicate]

This question already has answers here:
Does Java support Julian calendar?
(4 answers)
Closed 5 years ago.
I need to create a program that reads dates from a .csv file and convert it so that 13 days are added. I already did that but somehow it does not add the following dates as wished. It also goes over 30 days, which is not supposed to happen for example 2001-12-42.
public static void main(String[] args) throws FileNotFoundException, ParseException {
File fread = new File("src/daten-greg.csv");
File fwrite = new File("src/daten-jul.csv");
Scanner s = new Scanner(fread);
PrintStream print = new PrintStream(fwrite);
while(s.hasNext()) {
String[] line = s.nextLine().split(" ");
print.println(String.join(" ", Convert(line)));
}
s.close();
print.close();
}
private static String[] Convert(String[] value) throws ParseException {
for (int i = 0; i < value.length; i+=1)
value[i] = ToJulianisch(value[i]);
return value;
}
private static String ToJulianisch(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd");
Date d = sdf.parse(date);
Calendar c = Calendar.getInstance();
c.setTime(d);
int actDay = c.get(Calendar.DAY_OF_MONTH);
int actMonth = c.get(Calendar.MONTH) + 1 ;
int actYear = c.get(Calendar.YEAR);
actDay -= 13;
if(actDay - 13 < 1) {
actMonth -= 1;
if(actMonth < 1) {
actMonth = 12;
actYear -= 1;
}
Calendar k = Calendar.getInstance();
k.set(Calendar.YEAR, actYear);
k.set(Calendar.MONTH, actMonth - 1);
actDay = k.getActualMaximum(Calendar.DAY_OF_MONTH) + actDay;
}
return String.format("%s-%s-%s", actYear, actMonth, actDay);
}
You are subtracting 13 from actDay twice, first in actDay-=13 and again for if(actDay - 13 < 1). Inside the if block, you then add the value which is less than 14 to the number of days per month, resulting in overflowing the day of month.
If you simply want to subtract 13 days from the given date, you should use c.set(Calendar.DAY_OF_MONTH,actDay-13). This will handle the subtraction correctly inside the Calendar object and you can then use
actDay = c.get(Calendar.DAY_OF_MONTH);
int actMonth = c.get(Calendar.MONTH) + 1 ;
int actYear = c.get(Calendar.YEAR);
return String.format("%s-%s-%s", actYear, actMonth, actDay);
About some mistakes in your algorithm, see the answer of Heikki Mäenpää. I have also seen another mistake, namely a wrong pattern "yyyy-mm-dd" where "mm" stands for minutes (use "MM" for months).
But in general, you seem to try to reinvent the wheel. Even the old java.util.Calendar-API has a built-in way for the transformation from a gregorian to a julian calendar date, see my solution which is valid even for any date in the past with respect to cutover.
Your solution is only valid for dates where the distance between gregorian and julian calendar is 13 days (which is not true in the past, at the time of Pope Gregor's reform, there were only 10 days cut off).
public static void main(String[] args) throws ParseException {
String input = "2017-10-24";
System.out.println("Old API => " + toJulianisch(input)); // 2017-10-11
}
private static String toJulianisch(String date) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
GregorianCalendar gcal = new GregorianCalendar();
gcal.setTimeZone(TimeZone.getTimeZone("GMT"));
gcal.setGregorianChange(new Date(Long.MIN_VALUE));
sdf.setCalendar(gcal);
Date d = sdf.parse(date);
gcal.setGregorianChange(new Date(Long.MAX_VALUE));
gcal.setTime(d);
return sdf.format(d);
}
As you can see, the old API-stuff even forces you to set the timezone to a fixed offset to avoid any possible timezone clutter. This is necessary because java.util.Calendar and java.util.Date are not real calendar dates but instants/moments.
Side notice:
I have written a time library (Time4J) which can even handle any historic date equal if it was gregorian or julian (or even swedish), equal when the historic year started (was in most cases not the first of January!) etc. Maybe it is overkill for your problem but I mention it for the case you really want to operate with true historic calendar dates.

How to format date time in language independent way? [duplicate]

This question already has answers here:
Localized date format in Java
(6 answers)
Closed 8 years ago.
I need to show date and time in this format, Date: 9th Dec, Time: 19:20
Although my following code is working fine in English, have no idea this is correct way in other languages which my application is supporting like Chinese, Thai, etc. Any idea would be appreciated? Thanks
This is my code:
private String getFormattedTime(Calendar calendar)
{
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
StringBuilder sBuilder = new StringBuilder(4);
sBuilder.append(hour);
sBuilder.append(":");
// We want to display the hour like this: 12:09,
// but by not using following code it becomes 12:9
if (minute < 10)
{
sBuilder.append("0");
}
sBuilder.append(minute);
return sBuilder.toString();
}
private String getDateSuffix( int day)
{
if (day < 1 || day > 31)
{
throw new IllegalArgumentException("Illegal day of month");
}
switch (day)
{
case 1:
case 21:
case 31:
return ("st");
case 2:
case 22:
return ("nd");
case 3:
case 23:
return ("rd");
default:
return ("th");
}
}
I would recommend that you use Joda Time.
Here is an example from their Quick Start Guide.
DateTime dt = new DateTime();
String monthName = dt.monthOfYear().getAsText();
String frenchShortName = dt.monthOfYear().getAsShortText(Locale.FRENCH);
While "Dec" could mean December or décembre, Joda will use the correct one, depending on Locale.
Since Locale.CHINESE and Locale.THAI are available, it will do the translation for you.
If you use Java 8, Joda comes with the package.
You will save yourself a mountain of work if you use this package.
I did some research based on what #MadProgrammer said and this is my code for those how have same problem. DateFormat and SimpleDateFormat Examples.
private String getFormattedDate(Calendar calendar)
{
Date date = calendar.getTime(); // out: Dec 9, 2014
// String str = DateFormat.getDateInstance().format(date);
// Log.d(TAG, str);
String str = new SimpleDateFormat("MMM d").format(date);
// Log.d(TAG, str);
return str;
}
private String getFormattedTime(Calendar calendar)
{
Date date = calendar.getTime();
String str = DateFormat.getTimeInstance(DateFormat.SHORT).format(date);
// Log.d(TAG, str);
return str;
}

What is the easiest way to get the current day of the week in Android?

What would be the easiest way to get the current day of the week in Android?
The Java Calendar class works.
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
switch (day) {
case Calendar.SUNDAY:
// Current day is Sunday
break;
case Calendar.MONDAY:
// Current day is Monday
break;
case Calendar.TUESDAY:
// etc.
break;
}
For much better datetime handling consider using the Java 8 time API:
String day = LocalDate.now().getDayOfWeek().name()
To use this below Android SDK 26 you'll need to enable Java 8 desugaring in build.gradle:
android {
defaultConfig {
// Required when setting minSdkVersion to 20 or lower
multiDexEnabled true
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
}
More information on Android's Java 8 support: https://developer.android.com/studio/write/java8-support
Calendar calendar = Calendar.getInstance();
Date date = calendar.getTime();
// 3 letter name form of the day
System.out.println(new SimpleDateFormat("EE", Locale.ENGLISH).format(date.getTime()));
// full name form of the day
System.out.println(new SimpleDateFormat("EEEE", Locale.ENGLISH).format(date.getTime()));
Result (for today):
Sat
Saturday
UPDATE: java8
LocalDate date = LocalDate.now();
DayOfWeek dow = date.getDayOfWeek();
System.out.println("Enum = " + dow);
String dayName = dow.getDisplayName(TextStyle.FULL, Locale.ENGLISH);
System.out.println("FULL = " + dayName);
dayName = dow.getDisplayName(TextStyle.FULL_STANDALONE, Locale.ENGLISH);
System.out.println("FULL_STANDALONE = " + dayName);
dayName = dow.getDisplayName(TextStyle.NARROW, Locale.ENGLISH);
System.out.println("NARROW = " + dayName);
dayName = dow.getDisplayName(TextStyle.NARROW_STANDALONE, Locale.ENGLISH);
System.out.println("NARROW_STANDALONE = " + dayName);
dayName = dow.getDisplayName(TextStyle.SHORT, Locale.ENGLISH);
System.out.println("SHORT = " + dayName);
dayName = dow.getDisplayName(TextStyle.SHORT_STANDALONE, Locale.ENGLISH);
System.out.println("SHORT_STANDALONE = " + dayName);
Result (for today):
Enum = SATURDAY
FULL = Saturday
FULL_STANDALONE = Saturday
NARROW = S
NARROW_STANDALONE = 6
SHORT = Sat
SHORT_STANDALONE = Sat
Java 8 datetime API made it so much easier :
LocalDate.now().getDayOfWeek().name()
Will return you the name of the day as String
Output : THURSDAY
Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
or
new GregorianCalendar().get(Calendar.DAY_OF_WEEK);
Just the same as in Java, nothing particular to Android.
public String weekdays[] = new DateFormatSymbols(Locale.ITALIAN).getWeekdays();
Calendar c = Calendar.getInstance();
Date date = new Date();
c.setTime(date);
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
System.out.println(dayOfWeek);
System.out.println(weekdays[dayOfWeek]);
If you do not want to use Calendar class at all you can use this
String weekday_name = new SimpleDateFormat("EEEE", Locale.ENGLISH).format(System.currentTimeMillis());
i.e., result is,
"Sunday"
Here is my simple approach to get Current day
public String getCurrentDay(){
String daysArray[] = {"Sunday","Monday","Tuesday", "Wednesday","Thursday","Friday", "Saturday"};
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
return daysArray[day];
}
you can use that code for Kotlin which you will use calendar class from java into Kotlin
val day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
fun dayOfWeek() {
println("What day is it today?")
val day = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
println( when (day) {
1 -> "Sunday"
2 -> "Monday"
3 -> "Tuesday"
4 -> "Wednesday"
5 -> "Thursday"
6 -> "Friday"
7 -> "Saturday"
else -> "Time has stopped"
})
}
Using both method you find easy if you wont last seven days
you use (currentdaynumber+7-1)%7,(currentdaynumber+7-2)%7.....upto 6
public static String getDayName(int day){
switch(day){
case 0:
return "Sunday";
case 1:
return "Monday";
case 2:
return "Tuesday";
case 3:
return "Wednesday";
case 4:
return "Thursday";
case 5:
return "Friday";
case 6:
return "Saturday";
}
return "Worng Day";
}
public static String getCurrentDay(){
SimpleDateFormat dayFormat = new SimpleDateFormat("EEEE", Locale.US);
Calendar calendar = Calendar.getInstance();
return dayFormat.format(calendar.getTime());
}
Just in case you ever want to do this not on Android it's helpful to think about which day where as not all devices mark their calendar in local time.
From Java 8 onwards:
LocalDate.now(ZoneId.of("America/Detroit")).getDayOfWeek()
If you want to define the date string in strings.xml. You can do like below.
Calendar.DAY_OF_WEEK return value from 1 -> 7 <=> Calendar.SUNDAY -> Calendar.SATURDAY
strings.xml
<string-array name="title_day_of_week">
<item>日</item> <!-- sunday -->
<item>月</item> <!-- monday -->
<item>火</item>
<item>水</item>
<item>木</item>
<item>金</item>
<item>土</item> <!-- saturday -->
</string-array>
DateExtension.kt
fun String.getDayOfWeek(context: Context, format: String): String {
val date = SimpleDateFormat(format, Locale.getDefault()).parse(this)
return date?.getDayOfWeek(context) ?: "unknown"
}
fun Date.getDayOfWeek(context: Context): String {
val c = Calendar.getInstance().apply { time = this#getDayOfWeek }
return context.resources.getStringArray(R.array.title_day_of_week)[c[Calendar.DAY_OF_WEEK] - 1]
}
Using
// get current day
val currentDay = Date().getDayOfWeek(context)
// get specific day
val dayString = "2021-1-4"
val day = dayString.getDayOfWeek(context, "yyyy-MM-dd")
As DAY_OF_WEEK in GregorianCalender class is a static field you can access it directly
as foolows
int dayOfWeek = GregorianCalender.DAY_OF_WEEK;

Categories