Universal functions for showing date and time in any locale separately - android

I have a problem, I need the universal functions for showing date and time in any locale separately. But I can't find the way to do it without the checking the calendar.getLocale()
this function will give the date in US locale
static public String getDateFromCalendar(Calendar cal) {
return String.format("%tD", cal);
}
But if the Locale is russian I have to use istead this: String.format("%td.%tm.%tY", cal);
I don't want to use the conditional operations for every possible locale.
Please help to find the way to do is simplier.

Assuming you mean Java, I suggest you to consider the class java.text.DateFormat. Background is that every country/locale has its own typical date-time-format. For example:
public static String getDateFromCalendar(Calendar cal) {
// maybe get user-locale via ThreadLocal or via second method parameter
Locale locale = new Locale("ru", "Ru");
DateFormat dateFormat =
DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
return dateFormat.format(cal.getTime());
}
You can adjust the format style by choosing between SHORT, MEDIUM, LONG or FULL. For MEDIUM the output is: 05.04.2014 Compare that with the output for Locale.US yielding: Apr 5, 2014.

Related

MPAndroidChart x date value duplication problem

I am implementing the function to display the change of exercise time by date as a graph.
But there was a problem.
Before I explain the problem, I will briefly explain my code.
When a date is input from the user, the date is stored in the database and output by date.
For example, when the user enters 2020/06/26, it is displayed as 06/26 on the graph.
Now I will explain the problem.
The x value of the graph is overlapping. 07/01 does not appear immediately after 06/30, but very far.
I will attach my code and execution result. enter image description here
xAxis.setValueFormatter(new ValueFormatter() {
#Override
public String getFormattedValue(float value) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyMMdd");
Date date = null;
try {
date = simpleDateFormat.parse(Float.toString(value));
} catch (ParseException e) {
e.printStackTrace();
}
SimpleDateFormat newFormat = new SimpleDateFormat("MM/dd");
String dateString = newFormat.format(date);
return dateString;
}
});
Hard to tell from the code you provide. But most probably, the problem does not lie in the ValueFormatter, but in the actual x values you use. Having x values in the format yyMMdd ist most likely not what you want, because the difference between e.g. 2020-04-01 and 2020-04-02 is not the same as between 2020-03-31 and 2020-04-01, event if it should be exactly the same (1 day). You should use another representation for the x values, e.g. "days since 1970".
This still does not explain why 06-30 is displayed after 07-01 and even after 08-19, however. My guess is that your Entry list is not sorted properly in ascending order.

Different behavior of PeriodFormatter on different devices (JodaTime)

I'm implementing count down timer for the android app using JodaTime.
Depending of devices the output is different.
DateTime openingDateTime = new DateTime(2018, DateTimeConstants.JUNE, 14, 21, 0, 0, DateTimeZone.forID("Europe/Moscow"));
DateTime nowDateTime = DateTime.now(DateTimeZone.forID("Europe/Moscow"));
long difference = openingDateTime.getMillis() - nowDateTime.getMillis();
(...)
onTick(difference);
(...)
PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
.printZeroAlways()
.appendDays().appendSuffix(" day", " days")
.appendSeparator(" ")
.appendHours()
.appendSeparator(":")
.appendMinutes()
.appendSeparator(":")
.appendSeconds()
.toFormatter();
(...)
#Override
public void onTick(long millisUntilFinished) {
Duration duration = new Duration(millisUntilFinished);
Period period = duration.toPeriod(PeriodType.dayTime());
tvCounter.setText(periodFormatter.print(period));
}
On the one device output is correct: 491 days 4:39:18
on the other is wrong: 0 days 11788:49:11.
What am I doing wrong?
Thanks to your comments, I can now reproduce your problem. Just add following static initializer to your test class (at first place) to simulate the device where you observe your expected output:
static {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
}
According to the spec (see also the accepted answer on this SO-post), the conversion duration.toPeriod(periodType) should only use so-called precise duration fields, that is hours, minutes, seconds and milliseconds but not days.
My analysis of source code of Joda-Time (v2.9.6):
The internal class org.joda.time.chrono.BasicChronology contains following constant:
private static final DurationField cDaysField = new PreciseDurationField(DurationFieldType.days(), 86400000L);
So we see that here this duration field is marked as "precise", but: The subclass ZonedChronology wraps it and override the behaviour of method isPrecise():
public boolean isPrecise() {
return iTimeField ? iField.isPrecise() : iField.isPrecise() && this.iZone.isFixed();
}
This shows an extra zone dependency of the precision property of the days()-duration-field, namely precise for fixed zones like UTC and else imprecise.
I don't know if the analyzed and observed behaviour is a feature or a bug. Let's say, it is dangerous to expect the creation of Period-objects by duration.toPeriod(...) to be zone-independent. And it is not documented there to have a precise days-component if the system zone is fixed.
Unfortunately, the implicit dependency on the default time zone is deeply coded into Joda-Time via its chronology-design. As workaround, you can use:
Period p = new Period(nowDateTime, openingDateTime, PeriodType.dayTime());

Date not storing after iteration

I have an iteration that runs for a set number of times depending on another value which can vary which is why I'm using an iteration that iterates based on that value, inside that iteration I add 30 days to a date once each iteration and then add the results to a table.
PROBLEMS
I simply end up with the first instance of adding 30 days which is outside the iteration itself. This means that my values inside the iteration are not being stored properly but I can't see why.
I've checked the DateTime operations and displayed the value of newdate and it shows the proper date so it's most likely the storing of the date. But I don't know what's going wrong, it works pre-iteration which is what's got me confused. Why isn't it executing inside the iteration? Does anyone have any idea?
Ex.
InitialDate | 3/29/2015
2ndDate | 4/28/2015<-- This is what's stored which is pre-iteration
3rdDate | 5/28/2015<-- This is what it's supposed to be after the iteration
so on and so forth....
Values pre-iteration
//Date stuff
String startdate = (String.valueOf(Acc._date));
DateTimeFormatter formatter = DateTimeFormat.forPattern("MM-dd-yyyy HH:mm:ss");
DateTime dt = formatter.parseDateTime(startdate);
DateTime startpoint = new DateTime(dt);
DateTime whendue = startpoint.plusDays(30);
DateTime foriteration = whendue;
String formattedDate = whendue.toString(formatter);
//Storing initial date
pay.setDateDue(formattedDate);
db.AddPayment(pay);
Actual iteration
while (i < j) {
//Operation for Date Calculation
DateTime ndt = foriteration.plusDays(30);
foriteration = ndt;
String newdate = ndt.toString(formatter);
//Adding values to PayTable
pay.setDateDue(newdate);
db.AddPayment(pay);
i++;
}
Finally found out what was wrong. Nothing. My roommate played a prank on me and just got back from his trip out of town and explained to me how he changed my getDateDue to execute a plusDays(30) to mimic my code so that when I called AddPayment which calls getDateDue it would look like it would work but in actuality would only add 30 days once to the startdate no matter what I did.
Summary
Roommate is an ass, nothing is wrong with my code. Sorry for this pointless post.

Sony Xperia Date Issue

I came across the most weird problem with dates on a Sony Xperia LT26i. A date format: "hh:mm:ss a" will print "01:00 p.m." and on most devices it prints "01:00 pm". Any clue why is this? It is messing my joda time as I cant parse times that come from the server.
JodaTime can parse the local am/pm-strings your device produces. What to do with different strings coming from server? Since you expect fortunately only the markers "am" or "pm" from server I suggest to use two specialized formatter objects using am/pm-literals for parsing. So that is the workaround:
static final DateTimeFormatter AM_PARSER = DateTimeFormat.forPattern("hh:mm:ss 'am'");
static final DateTimeFormatter PM_PARSER = DateTimeFormat.forPattern("hh:mm:ss 'pm'");
public static LocalTime parseServer(String input) {
if (input.endsWith("am")) {
return AM_PARSER.parseLocalTime(input);
} else {
LocalTime lt = PM_PARSER.parseLocalTime(input);
return lt.plusHours(12); // necessary because we parse pm only as literal
}
}
Explanation:
If you study the JodaTime-source code then you will find that am/pm-strings finally come from DateFormatSymbols.getInstance(locale).getAmPmStrings(). So the question arises why you have "p.m." instead of "pm" on Sony Xperia device. This leads to the question what is the data source of class DateFormatSymbols. This is dependent on the JVM-provider who manages such data in any resource directory (in your case dependent on your special Android configuration, in my case in resource bundle class sun.text.resources.FormatData). It is really different for every JVM (and Android is not even an official Java-VM).
After thinking a little bit I have come up with this solution
public static LocalTime localTimeParse(String date, DateTimeFormatter dateTimeFormatter) {
if(!StringUtils.hasText(date) || dateTimeFormatter == null)
return null;
LocalTime localTime = null;
try {
localTime = LocalTime.parse(date,dateTimeFormatter);
} catch(IllegalArgumentException exception) {
//This can happen on devices that have their time in the following format "01:00 p.m." insetad of "01:00 pm"
//Sony Xperia lT26i is one of them
String newDate = date.toLowerCase(Locale.getDefault()).contains("am") ? date.toLowerCase(Locale.getDefault()).replace("am", "a.m.") : date.toLowerCase(Locale.getDefault()).replace("pm", "p.m.");
localTime = LocalTime.parse(newDate,dateTimeFormatter);
}
return localTime;
}
This can be used like this:
DateTimeFormatter formatter = DateTimeFormat.forPattern("hh:mm a");
LocalTime localTime = DateUtils.localTimeParse("09:00 PM",formatter);
It works on Xperia a non Xperia

DecimalFormat("#0.000") doesn't format the right way like 1.321 instead of this it delievers 1,321

I want to get a Double with 3 decimalplaces. I do this:
String sAveragePrice;
Double dAveragePrice = holePrice/(allPrices.size()); // delivers 1.3210004
DecimalFormat threeZeroes = new DecimalFormat("#0.000");
sAveragePrice = threeZeroes.format(dAveragePrice); // delivers then 1,321
After formatting I dont get a 1.321 but 1,321. And the 1,321 throws a NumberformatException later. This is when it is thrown:
Double priceInt = Double.parseDouble(sAveragePrice); // throws NumberFormatException
The strange thing is, I have this code till 3 weeks and it didn't make any problem. But today when I have started my app again it gets problem with it. But I didn't have changed anything.
Can anybody help me? I also tried this:
NumberFormat format = NumberFormat.getNumberInstance();
format.setMinimumFractionDigits(3);
format.setMaximumFractionDigits(3);
sAveragePrice = format.format(dAveragePrice);
But it also delivers me a "," instead of a "." for double.
Try using a locale for you number format.
Number format = NumberFormat.getNumberInstance(Locale.ITALIAN);
Java SDK has a limited number of predefined locale settings, so for other locales (e.g., for Russian), you can use the following snippet:
Number format = NumberFormat.getNumberInstance(new Locale("ru", "RU"));
Number format = NumberFormat.getNumberInstance(new Locale("it", "IT")); // etc...
this sample code may help you...
Locale locale = Locale.getDefault();
// set Locale.US as default
Locale.setDefault(Locale.US);
DecimalFormat decimalFormat = new DecimalFormat("##.000");
double d = 14.5589634d;
String format = decimalFormat.format(d);
System.out.println(format);// prints 14.559
// back to default locale
Locale.setDefault(locale);
Have a look at this SO question
How to change the decimal separator of DecimalFormat from comma to dot/point?
Basically your output will be Locale specific, so if you have a Locale of Frame then it will be different to a Locale of the US.
try
NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
Use this type of formatting
use # instead of 0. It is the correct format to declare your pattern
String sAveragePrice;
Double dAveragePrice = holePrice/(allPrices.size());
DecimalFormat threeZeroes = new DecimalFormat("#.###");
sAveragePrice = threeZeroes.format(dAveragePrice);
Hope it will help you

Categories

Resources