Why does Calendar.getTimeInMillis() returns negative value? - java

I am reading the date of a textview and i want to know the unix time at 00.00 am.
Working with API 23.
Following is my shot at achieving it:
String sDate = mainBinding.tvTakeTimeCurrentShownDateDateFormat.getText().toString();
Calendar actuallDate = Calendar.getInstance();
Log.d(TAG, "oc_bt_TakeTime_lastDate: " + sDate.substring(6,8)+ " " + Integer.parseInt(sDate.substring(6,8)));
Log.d(TAG, "oc_bt_TakeTime_lastDate: "+ sDate.substring(3,5) + " " + Integer.parseInt(sDate.substring(3,5)));
Log.d(TAG, "oc_bt_TakeTime_lastDate: " + sDate.substring(0,2) + " " + Integer.parseInt(sDate.substring(0,2)));
actuallDate.clear();
actuallDate.set(Integer.parseInt(sDate.substring(6,8)), (Integer.parseInt(sDate.substring(3,5))-1), Integer.parseInt(sDate.substring(0,2)), 0, 0 ,0);
Log.d(TAG, "oc_bt_TakeTime_lastDate: " + actuallDate.get(Calendar.DAY_OF_MONTH)+actuallDate.get(Calendar.MONTH)+actuallDate.get(Calendar.YEAR));
Log.d(TAG, "oc_bt_TakeTime_lastDate: " + String.valueOf(actuallDate.getTimeInMillis()));
I casted it to long because I thought it might produce an overflow by casting to an int.
result:
oc_bt_TakeTime_lastDate: 19 19
oc_bt_TakeTime_lastDate: 08 8
oc_bt_TakeTime_lastDate: 24 24
oc_bt_TakeTime_lastDate: 24719
oc_bt_TakeTime_lastDate: -61547472000000

As you can see on the second-to-last display, you are setting the year 0019, not the year 2019. As getTimeInMillis is set in relation to the epoch time (Jan 1, 1970), you get a negative number.

You are overcomplicating things.
java.time and ThreeTenABP
I could not read from your question exactly how your string looks. For this answer I am assuming 24.08.19. If you cannot adapt the answer to your real string, please revert in comments.
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("dd.MM.uu");
String sDate = "24.08.19";
LocalDate actualDate = LocalDate.parse(sDate, dateFormatter);
System.out.println("Actual date: " + actualDate);
long epochMilli = actualDate.atStartOfDay(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
System.out.println("Milliseconds since the epoch: " + epochMilli);
Output on my computer in Europe/Copenhagen time zone is:
Actual date: 2019-08-24
Milliseconds since the epoch: 1566597600000
The Calendar class that you were trying to use is poorly designed and long outdated. You should not use it. For a date use LocalDate from java.time, the modern Java date and time API.
Don’t hand parse your string the way you were doing. The DateTimeFormatter class has been built in for this purpose, so leave the work to it. This also buys you a better validation of the string. uu or yy in a format pattern string will parse a 2-digit year like 19 into a year in the interval from 2000 through 2099.
What went wrong in your code?
jmart is correct: You were setting the year to year 19 common era. That’s 2000 years ago now. Since the epoch from which the milliseconds are counted was in 1970, you’re bound to get a negative number. As you have seen, using the formatter for parsing solves this problem for you.
Question: Can I use java.time on Android API level 23?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

I'll suggest this workaround:
Create a Date object using current timestamp
Use that object to set your calendar object
Date d = new Date(timestampLong);
Calendar actuallDate = Calendar.getInstance();
actuallDate.setTime(d);

Related

Converted unix timestamp with a timezone addition in seconds gives a true local date time on Android emulator but not in real device?

I took a date from a web service in UNIX timestamp. I milltuplied it by 1000L then I added the timezone to it in seconds (also provided by the web service) milltiplied by 1000 to obtain the date according to the country in which the application will run and not the UTC date.
In the emulator the date time provided is correct but when I tested on a real device it provided me the time with 1 hour more which does not correspond to the local time. Where is the problem?
long numberOfsecondsRise = json.getJSONObject("city").getInt("timezone");
long res=(json.getJSONObject("city").getLong("sunrise")*1000L +numberOfsecondsRise*1000) ;
Date rise=new java.util.Date(res);
DateFormat dfa = DateFormat.getTimeInstance();
sunFiled.setText(getResources().getString(R.string.sunrise)+": " + dfa.format(rise));
java.time and ThreeTenABP
Consider using java.time, the modern Java date and time API, for your time work. If for minSDK below API level 26, then through the backport, I will get back to that. First the code:
DateTimeFormatter timeFormatter
= DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
long sunriseUnixTs = 1_589_581_234;
ZonedDateTime sunriseApplicationTz = Instant.ofEpochSecond(sunriseUnixTs)
.atZone(ZoneId.systemDefault());
System.out.println("Sunrise: " + sunriseApplicationTz.format(timeFormatter));
Output from this example snippet in my time zone and locale:
Sunrise: 03.50.34
One of the things I find great about java.time is that the code makes it explicit that we are getting the time in the default time zone of the JVM where the application is running.
What went wrong in your code?
Adding the time zone offset of the city you are inquiring about is wrong. A Unix timestamp is independent of time zone. So if you multiply by 1000 and feed to new Date(long), you are getting a Date that holds the correct point in time. If you add a non-zero offset, you are getting a wrong point in time. Your emulator gave you the expected result, why, then? It might be because the offset from JSON was 0 (zero) or because the error was balanced out by the emulator using a different default time zone from what you had expected.
Question: Doesn’t java.time require Android API level 26?
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
A question about an Android emulator that seems to be using UTC as its default time zone rather than the time zone of the host operating system: Emulated Android Device shows wrong date (Windows 10)
Date (long date) constructor documentation says:
Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.
This means the value is supposed to be in UTC. The time offset in seconds must be applied when formatting the date for display.
long numberOfsecondsRise = json.getJSONObject("city").getInt("timezone");
Date rise = new java.util.Date(json.getJSONObject("city").getLong("sunrise") * 1000L);
int offsetMinutes = numberOfsecondsRise / 60;
String sign = (offsetMinutes < 0 ? "-" : "+");
offsetMinutes = Math.abs(offsetMinutes);
String timeZoneID = String.format("GMT%s%d:%02d", sign, offsetMinutes / 60, offsetMinutes % 60);
DateFormat dfa = DateFormat.getTimeInstance();
dfa.setTimeZone(TimeZone.getTimeZone(timeZoneID));
sunFiled.setText(getResources().getString(R.string.sunrise) + ": " + dfa.format(rise));

Calendar.setTimeInMillis error - why is that? [duplicate]

This question already has answers here:
Java: Date from unix timestamp
(11 answers)
Closed 3 years ago.
calendar gets wrong unix time as I got.
long millis = 1568814839L;
System.out.println(millis); //1568814839
Calendar.getInstance(TimeZone.getTimeZone("Asia/Tashkent"));
calendar.setTimeInMillis(millis);
System.out.println(calendar.get(Calendar.MILLISECOND));//839
What should I do? Calendar.YEAR should be 2019 with that millis. However, calendar gives me 1970, why?
The error is due to you confusing time in milliseconds and time in seconds. 1568814839L is the number of seconds since 1/1/1970, but you're treating it as milliseconds. This is quite easy to check:
long millis = 1568814839L;
System.out.println(millis); //1568814839
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tashkent"));
System.out.println(calendar.getTimeInMillis()); //1568820981321
calendar.setTimeInMillis(millis);
System.out.println(calendar.get(Calendar.YEAR));//839
This will produce:
1568814839
1568820981321
1970
As you can see, your number is 3 orders of magnitude off. Add three 0's to the end of your millis number:
long millis = 1568814839000L;
...
System.out.println(calendar.get(Calendar.YEAR));
Now you get:
1568814839000
1568821211006
2019
java.time
The modern code would use java.time, the modern Java date and time API.
Feed your count of whole seconds since 1970-01-01T00:00Z to the Instant class:
ZonedDateTime zdt = Instant.ofEpochSecond(1_568_814_839L)
.atZone(ZoneId.of("Asia/Tashkent"));
System.out.println(zdt);
System.out.println("Year: " + zdt.getYear());
System.out.println("Millisecond of second: "
+ zdt.get(ChronoField.MILLI_OF_SECOND));
Output is:
2019-09-18T18:53:59+05:00[Asia/Tashkent]
Year: 2019
Millisecond of second: 0
As others have said, your number is seconds since the epoch, not milliseconds.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

Convert API timezone in seconds to GMT timezone. Also convert API temperature to deg celcius

I am getting API weather data from some weather website.
It has provided me timezone as 19800 which I want to convert to GMT + 05:30 but I am not able to do the same.
Also it has given temperatures as 297.58 which I want to convert to deg Celcius.
I tried assuming that given temperature as deg Kelvin and reducing 273 from it but it is not working
I want to be able to convert seconds to time zone and show temp in degree celcius.
Offset conversion using java.time
It’s simple when you know how:
int offsetSeconds = 19_800;
ZoneOffset offset = ZoneOffset.ofTotalSeconds(offsetSeconds);
System.out.println("Offset is " + offset);
Output is:
Offset is +05:30
Next you may use the obtained ZoneOffset object to convert the date and time. The details depend on the format of your date and time.
Temperature conversion
I agree that your temperature looks very much like degrees Kelvin. If so, the formula given in the other answer by #Lt . Null is correct:
double temperatureKelvin = 297.58;
double temperatureCelsius = temperatureKelvin - 273.15;
System.out.println("Temperature is " + temperatureCelsius + " degrees Celsius");
Temperature is 24.430000000000007 degrees Celsius
The many decimals come from floating point math most often being inaccurate. (For accuracy, use BigDecimal instead.) For output to the user you may want to print fewer decimals. If so, format the number using NumberFormat and/or DecimalFormat.
If 24.43 °C disagrees with your expectation, you need to tell us what you had expected instead, at the very least.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
For your timezone converter use this
long unix_seconds = 19800;
Date date = new Date(unix_seconds*1000L);
// format of the date
SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
formate.setTimeZone(TimeZone.getTimeZone("GMT+5:30"));
String dateFinal = formate.format(date);
System.out.println("\n"+dateFinal+"\n");
And finding kelvin to degree just use 297.58K − 273.15 = 24.43°C

How to get time entered by user in EditText and deduct 5 hrs 30 minutes from it?

I had two edit text for user to enter time (24 hours format).
How could i get those times from Edittext and deduct 5 hours and 30 minutes from user selected time.
Reason for deducting time : Converting IST to UTC timezone.
My final output should be like - HH:MM:SS:Milleseconds (Ex : 18:25:30:245635).
Thanks in advance.
java.time
ZoneId zone = ZoneId.of("Asia/Kolkata");
String timeString = "18:25:30.245635";
LocalTime time = LocalTime.parse(timeString);
LocalTime utcTime = LocalDate.now(zone) // Today
.atTime(time) // Today at the time in question
.atZone(zone) // Date and time in IST
.toOffsetDateTime() // Convert to OffsetDateTime for the next step
.withOffsetSameInstant(ZoneOffset.UTC) // Convert to UTC
.toLocalTime(); // Extract only the time of day
System.out.println("UTC time: " + utcTime);
Output is:
UTC time: 12:55:30.245635
I have assumed today’s date. Please check if this assumption is right for you. While the UTC offset for Asia/Kolkata hasn’t changed much recently, other time zones change their offset twice a year.
I changed your time format to have a period (point) rather than a colon between the seconds and fraction of second as is customary. If you do require a colon there, you need a DateTimeFormatter for parsing.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601

How to parse time (hour, minute) from a string?

Anybody know how to parse time (hour, minute and AM/PM) from a string that looks like "01:20" -> 1:20AM and "21:20" -> 9:20PM? Most solutions out there seem to assume or require a Date or Calendar object.
My input time is actually coming from a TimePickerDialog (specifically, this MaterialDateTimePicker implementation, so I receive only the hourOfDay, minute and seconds (integers).
I want to be able to format the time that the user picked in a friendly way, i.e 12:30PM, 02:15AM, etc.
I am trying to use Joda Time:
fun formattedTime(timeStr: String): String {
// Get time from date
val timeFormatter = DateTimeFormat.forPattern("h:mm a")
val displayTime = timeFormatter.parseLocalTime(timeStr)
return displayTime.toString()
}
but I get this error with an input string such as "1:20":
java.lang.IllegalArgumentException: Invalid format: "1:20" is too short
I have also looked into SimpleDateFormat but it seems to require a full date-time string such as in this related question
As #ole-v-v pointed out, SimpleDateFormat has seen better days - so today you can make use of the java.time package to do the job:
java.time.format.DateTimeFormatter target2 =
java.time.format.DateTimeFormatter.ofPattern("h:mm a");
java.time.format.DateTimeFormatter source2 =
java.time.format.DateTimeFormatter.ofPattern("HH:mm");
System.out.println("01:30 -> " + target2.format(source2.parse("01:30")));
System.out.println("21:20 -> " + target2.format(source2.parse("21:20")));
Yields the result of
01:30 -> 1:30 AM
21:20 -> 9:20 PM
as expected.
In Joda-Time you would code it as #meno-hochschild pointed out in his answer below.
Using SimpleDateFormat it will look like this:
SimpleDateFormat target = new SimpleDateFormat("h:mm a");
SimpleDateFormat source = new SimpleDateFormat("HH:mm");
System.out.println("01:30 -> " + target.format(source.parse("01:30")));
System.out.println("21:20 -> " + target.format(source.parse("21:20")));
This will parse from 24h times to 12 hours display
01:30 -> 1:30 AM
21:20 -> 9:20 PM
It all depends on the format for the hours - for parsing you'll want 24h hours (format HH), for output you want 12 hours plus am / pm - format is h.
If you want 01:30 to be PM you'll have to add that to the string to be parsed somehow:
System.out.println("01:30 pm-> " + target.format(target.parse("01:30 pm")));
resulting in
01:30 pm-> 1:30 PM
The accepted answer is correct. However, I am astonished to see the old classes like SimpleDateFormat although the OP has explicitly first desired a Joda answer (see the tags of the question). So I post here the Joda answer as supplement:
DateTimeFormatter target = DateTimeFormat.forPattern("h:mm a").withLocale(Locale.ENGLISH);
DateTimeFormatter source = DateTimeFormat.forPattern("HH:mm");
System.out.println("01:30 -> " + target.print(source.parseLocalTime("01:30")));
System.out.println("21:20 -> " + target.print(source.parseLocalTime("21:20")));
01:30 -> 1:30 AM
21:20 -> 9:20 PM
I advise not to mix two different time libraries (the OP obviously uses Joda-Time-Android).
Your two good options are Joda-Time and java.time.
Since you receive hourOfDay, minute and seconds as integers from the time picker, you don’t need to do any parsing.
java.time
DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
.withLocale(Locale.US);
LocalTime time = LocalTime.of(hourOfDay, minute, second);
String displayTime = time.format(timeFormatter);
System.out.println(displayTime);
This prints the time like this:
11:45 PM
Rather than an explicit format pattern string I am relying on the built-in localized format for the US locale. It has put a space between the minutes and PM (or AM). I believe your users will be happy about that. If not, you will need to use DateTimeFormatter.ofPattern("h:mma", Locale.US) instead.
Joda-Time
If you are already using Joda-Time and don’t have a reason for changing at this point, sticking to it is reasonable. You may use the LocalTime(int hourOfDay, int minuteOfHour, int secondOfMinute) constructor. Then proceed as in Meno Hochschild’s answer. It’s a good and knowledgeable answer.
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).
(Quoted from the Joda-Time homepage)
Stay away from SimpleDateFormat
Stay far away from the SimpleDateFormat class. It can be made to work for the job, but it is not only long outdated, it is also notoriously troublesome.
Question: Can I use java.time on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.timeto Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.

Categories

Resources