I have a number format in a file that Matlab converts to a date string. The format is structured, for example, as 732161.8561226851.
When I perform datestr(732161.8561226851) in Matlab, I get:
ans =
'02-Aug-2004 20:32:49'
I wish to achieve the same output but as a Java function. I haven't seen this format before, however, and am unsure of the conversion process taken.
What is the process to convert this into a date string so I can create a Java function?
// Matlab epoch is January 0, 0000, so subtract 1 day from January 1:
Instant matlabEpoch = Instant.parse("0000-01-01T00:00:00Z").minus(1, ChronoUnit.DAYS);
Instant inst = matlabEpoch.plusMillis(
Math.round(732161.8561226851 * TimeUnit.DAYS.toMillis(1)));
System.out.println(inst);
This prints:
2004-08-02T20:32:49Z
I trust that #Riley Jacob’s answer is correct and see that it uses the long outdated Date class. So I wanted to give a modern version of the same answer. Other than avoiding the old-fashioned class it also has the advantage of leaving most of the calculation to library methods, which in turn gives clearer code.
I find it worth noting that we hit the same result as Matlab with millisecond precision. If the result had been one millisecond off, it would have been printed as either 2004-08-02T20:32:48.999Z or 2004-08-02T20:32:49.001Z.
Link: Oracle tutorial: Date Time explaining how to use java.time.
The format is MATLAB's DateNumber: the number of days elasped since January 0, 0000. You can use Java's toUTCString with some modifying:
var d = new Date(dateMATLAB*86400000-62167305600000);
var n = d.toUTCString();
Where dateMATLAB is MATLAB's date output. The value 62167305600000 is the number of milliseconds which elapsed between year 0 and 1970. Using your example,
var d = new Date(732161.8561226851*86400000-62167305600000);
var n = d.toUTCString();
Will output
Mon, 02 Aug 2004 20:32:48 GMT
Related
I'm developing an android application and I use GSON to get the data from the server, I'm working on both APIs of Facebook and Imgur and the same issue happens. How can I convert a date from milliseconds format to a human-readable format like for example 1584780523 and I want to convert it to any format, for example, 25, Mar 2020.
What I tried to do!
• Get Data
#SerializedName("datetime")
#Expose
private long datetime;
// setters and getters
• In my adapter after getting DATETIME I parse it to a human-readable format
// Get Datetime.
long getDate = data.getDatetime();
// Parse it in this format for example.
DateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy HH:mm:ss:SSS Z");
Date result = new Date(getDate);
// Set Result (Human-Readable date)
date.setText(dateFormat.format(result));
• But here is the problem! It gives me date like this
19 Jan 1970 09:54:00:533 +0200
Why the output at the 1970s. I saw something like that is the default output of Datetime? But in the same case, it gives me on the other items on my RecyclerView the same output but the last three digits changes!
Here what I'm asking!
1- Why we use (a lot of people use long instead of int?
2- Why the output gives me that and how can I fix this?
3- In other APIs like Youtube they use the regular DateTime why Facebook and Imgur changes them?
Note: I searched about my question for 3 days but I didn't get any answers or relative questions on StackOverflow so, I asked here. All of them or most are for PHP and JavaScript I need an example in Java Android Studio
Thanks.
Your 1584780523 value is in seconds, not milliseconds.
long secondsSinceEpoch = 1584780523;
long millisSinceEpoch = secondsSinceEpoch * 1000L;
Date date = new Date(millisSinceEpoch);
System.out.println(date);
SimpleDateFormat fmt = new SimpleDateFormat("d, MMM yyyy", Locale.US);
System.out.println(fmt.format(date));
Output1
Sat Mar 21 04:48:43 EDT 2020
21, Mar 2020
1) I'm in America/New_York time zone
1- Why we use (a lot of people use long instead of int?
This is to avoid the year 2038 problem. While for example 1584780523 does fit into an int (a 32 bits signed integer), only dates and times up to January 19 2038 03:14:07 UTC can be represented. When writing a program today, we cannot be very sure that no one will ever use our code for dates and times after that point. So we use long instead. After the year 2000 problem (using two digit years leading to problems for dates in year 2000 and later) I guess the IT world has made a sort of a commitment not again to use date and time representations that have an end date within our lifetime.
2- Why the output gives me that and how can I fix this?
Andreas has already explained this part: Because you were treating your seconds as milliseconds. It’s a common mistake.
BTW I recommend using a proven library for the conversion. The comments have already mentioned:
Instant.ofEpochSecond(timestamp)
While multiplying by 1000 works (on a long, not on an int because of overflow), doing your date and time conversions by hand is a bad habit to get into because they very often get more complicated than you think, and the risk of errors is great. Also using a library method with a nice name much better conveys why you are multiplying by 1000.
3- In other APIs like Youtube they use the regular DateTime why
Facebook and Imgur changes them?
I guess it’s because they didn’t know better back when they designed the API. There’s an international standard for transmitting dates and times, ISO 8601, and using it efficiently prevents mistakes like yours, so this is what they should have used. Even if they have understood that later, now a lot of programs rely on the old way, so changing it now would also be risky.
Links
Wikipedia article: Year 2038 problem
A few related Stack Overflow questions out of many:
Java: Date from unix timestamp
Converting Long to Date in Java returns 1970
android timestamp parsing gone wrong(always in 1970)
Wikipedia article: ISO 8601
I've been trying to read the binary file with Java, and the binary file is written in C#. And some of those data is contain a DateTime data.
When DateTime data will be written into the file (in binary), it using DateTime.ToBinary(); on C#.
For reading the DateTime data, it will convert first from bytes into long data, using BitConverter.ToInt64(byte[], 0), and then convert it again from long into DateTime data using DateTime.FromBinary(long). (All of those are written in C#).
Let's say the long data after converting from bytes is = -8586803256090942249, and when convert it into DateTime, it will return = 3/17/2018 5:07:56 PM
Now, I'm trying to read that binary file with Java. And for converting the bytes data into long data, I'm using this code : ByteBuffer.wrap(byte[]).order(ByteOrder.LITTLE_ENDIAN).getLong().
It will return the exact long data value as C# did. But when I try to convert it from long data into DateTime in Java, using Date date = new Date(long), it will return = Sun May 06 19:04:17 WIB 272097407 instead.
Can you help me what is the correct solution for this ? Is there any equivalent for DateTime.FromBinary() from C# in Java ? Or is my code wrong ? All of yours answers is really appreciated.
In Java:
long fromBytes = -8586803256090942249L;
// Mask out kind and ticks
int kind = Math.toIntExact((fromBytes >> 62) & 0x3);
long ticks = fromBytes & 0x3FFF_FFFF_FFFF_FFFFL;
LocalDateTime cSharpEpoch = LocalDate.of(1, Month.JANUARY, 1).atStartOfDay();
// 100 nanosecond units or 10^-7 seconds
final int unitsPerSecond = 10_000_000;
long seconds = ticks / unitsPerSecond;
long nanos = (ticks % unitsPerSecond) * 100;
LocalDateTime ldt = cSharpEpoch.plusSeconds(seconds).plusNanos(nanos);
switch (kind) {
case 0: // Unspecified
case 2: // Local time
System.out.println("Result LocalDateTime: " + ldt);
break;
case 1: // UTC
OffsetDateTime utcDateTime = ldt.atOffset(ZoneOffset.UTC);
System.out.println("Result OffsetDateTime in UTC: " + utcDateTime);
break;
default:
System.out.println("Not a valid DateTimeKind: " + kind);
break;
}
Output:
Result LocalDateTime: 2018-03-17T10:07:56.383355900
Edit: The number is
A 64-bit signed integer that encodes the Kind property in a 2-bit
field and the Ticks property in a 62-bit field.
Tetsuya Yamamoto was correct so far as the ticks property denotes number of 100-nanosecond intervals elapsed since 0001/01/01 at start of day (midnight). The kind is either 0 for unspecified, 1 for UTC or 2 for local time. So I am masking the kind and the ticks out separately.
Even though the kind is 2 in your case, which should be for local time, it seems that the time is indeed in UTC. It’s the only way that the time printed could agree with your expected 5:07:56 PM Western Indonesian Time. Maybe the number was generated on a computer with its time zone set to UTC.
To get the time in your time zone:
ZoneId targetZone = ZoneId.of("Asia/Jakarta");
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC).withZoneSameInstant(targetZone);
System.out.println("Converted to target time zone: " + zdt);
Converted to target time zone: 2018-03-17T17:07:56.383355900+07:00[Asia/Jakarta]
This agrees with what you said you got on the C# side.
PS Avoid the Date class in Java if you can, it is long outdated and poorly designed and was replaced many years ago now by java.time, the modern Java date and time API (which I am of course using in the above). If you do need a Date for a legacy API that you cannot change or don’t want to change just now, as you already noted in a comment, the conversion is like this:
Instant inst = ldt.atOffset(ZoneOffset.UTC).toInstant();
Date date = Date.from(inst);
System.out.println(date);
Output on a JVM with default time zone Asia/Jakarta:
Sat Mar 17 17:07:56 WIB 2018
Acknowledgement: Andreas in an answer (link below) explained the structure of the 64 bits number and gave the link to the documentation. I have taken them from there.
Links
DateTime.FromBinary(Int64) Method from the .NET documentation
Andreas’ answer to a duplicate question
I'm trying to convert 5007 to HH:mm:ss:SSS, I'm using Netbeans IDE v8.2:
Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
String dateFormatted = formatter.format(date);
But this gives me an incorrect result:
01:00:05:007
^^-------------------------why does it print to me 01 in the hours?
But it should get:
00:00:05:007
^^-------------------------correct result
When I use ideone for example it gives me a correct result:
Any explication about this problem?
I testes with both versions: Java 7 and Java 8.
When you ask for the explanation of your problem I will be honest with you: You are misusing SimpleDateFormat for formatting a duration. It was never meant for this use and is not designed to give you the expected result if you try it anyway. The problem you got is not the only problem you will have. If your duration grows to more than 24 hours, the whole days will not be formatted, so your result will be wrong in a different way.
Apart from that, these days I recommend not using the SimpleDateFormat class at all. Its replacement is java.time.format.DateTimeFormatter, it came out in 2014 and comes with quite fewer negative surprises. It is not a good choice for formatting a duration either, though.
So what is a good choice? I will give you the Java 9 answer first because it is easy:
Duration dur = Duration.ofMillis(5007);
String hmss = String.format("%02d:%02d:%02d:%03d",
dur.toHours(),
dur.toMinutesPart(),
dur.toSecondsPart(),
dur.toMillisPart());
The main advantage isn’t even the ease, it’s the clarity. For example, with this code no one needs to ask the question I asked in a comment, is it a point it time or a duration? The code very clearly states that it is a duration.
For Java 6, 7 and 8, you may still use the Duration class (in Java 6 and 7 through the ThreeTen Backport), but it doesn’t lend itself that easily to formatting, so I think I would resort to using the TimeUnit enum as in the question I had linked to (the link you asked me to remove again):
long millis = 5007;
long hours = TimeUnit.MILLISECONDS.toHours(millis);
millis -= TimeUnit.HOURS.toMillis(hours);
long minutes = TimeUnit.MILLISECONDS.toMinutes(millis);
millis -= TimeUnit.MINUTES.toMillis(minutes);
long seconds = TimeUnit.MILLISECONDS.toSeconds(millis);
millis -= TimeUnit.SECONDS.toMillis(seconds);
String hmss = String.format("%02d:%02d:%02d:%03d", hours, minutes, seconds, millis);
The result is the desired
00:00:05:007
To illustrate the point I was trying to make about what happens when the duration is more than 24 hours, let’s try to give it 100 000 000 milliseconds (there are 86 400 000 millis in a day):
27:46:40:000
Date date = new Date(5007);
creates a Date which is 5007 milliseconds after January 1, 1970, 00:00:00 GMT.
When you format it with SimpleDateFormat, it is converted to your machine's timezone (which I'm assuming is GMT+1).
When I run your code I get
02:00:05:007
And my timezone is GMT+2.
If you set the timezone of the DateFormat instance to GMT, you'll get the expected output:
Date date = new Date(5007);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
formatter.setTimeZone (TimeZone.getTimeZone ("GMT"));
String dateFormatted = formatter.format(date);
System.out.println (dateFormatted);
This prints
00:00:05:007
It is definitely a Locale issue. When you do not specify one it will use the (your system) default one. To override this;
try either adding this
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
or passing a Locale when constructing the SimpleDateFormat instance. For example:
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS", Locale.ENGLISH);
I assume Locale.ENGLISH has UTC timezone btw, but I hope you get the idea.
My need is that I have a value in Long, which represent the milliseconds value since epoch. I wish to find out the difference in the number of days between that day and the current day.
I am using Java8's DAYS.between(inputDate, currentDate)
For the currentDate I have used LocalDateTime currentDate = LocalDateTime.now();
But the issue I am facing is when I am converting the long value into java8 LocalDateTime. When I use
LocalDate date = Instant.ofEpochMilli(1490372528)
.atZone(ZoneId.systemDefault())
.toLocalDate();
The result is 1970-01-18 while when I enter the same value in https://www.epochconverter.com/ it gives Fri, 24 Mar 2017 16:22:08 GMT
Why is this discrepancy there? How to effectively get a java8 date from a long value to use in DAYS.between()?
You have to decide. Either, your number is “milliseconds value since epoch”, as you stated in your question, or it is “number of seconds that have elapsed since January 1, 1970”, as stated (and used) on the linked web site.
If it is truly “milliseconds since epoch”, you can use
System.out.println(Instant.ofEpochMilli(1490372528).until(Instant.now(), ChronoUnit.DAYS));
to print the number of days, which is, by the way, not simpler than the pre-Java 8 code
System.out.println(TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis()-1490372528));
If your number actually is “seconds since epoch”, you have little to change in your code
System.out.println(Instant.ofEpochSecond(1490372528).until(Instant.now(),ChronoUnit.DAYS));
which is equivalent to
System.out.println(ChronoUnit.DAYS.between(Instant.ofEpochSecond(1490372528),Instant.now()));
as you mentioned DAYS.between explicitly. It will just delegate to the until method used above. The equivalent pre-Java 8 code would be slightly more complicated
System.out.println(TimeUnit.MILLISECONDS.toDays(
System.currentTimeMillis()-TimeUnit.SECONDS.toMillis(1490372528)));
I need to convert some epoch time stamps to the real date and have used some of the methods I found on stack overflow, but they give the wrong answer.
As an example, one date is "129732384262470907" in epoch time, which is "Mon, 20 Jan 6081 05:24:22 GMT" using http://www.epochconverter.com/
However, my code generates: "Wed Dec 24 14:54:05 CST 19179225"
String epochString = token.substring(0, comma);
long epoch = Long.parseLong(epochString);
Date logdate = new Date(epoch * 1000);
BufferedWriter timewrite = new BufferedWriter(new FileWriter(tempfile, true));
timewrite.write(logdate);
timewrite.flush();
timewrite.close();
The initial timestamp is in miliseconds, which in the examples I saw here I am supposed to multiply by 1000.
If I don't multiply by 1000, I get: "Mon Aug 08 01:14:30 CDT 4113025"
Both of which are wrong.
So where have I made my error?
129732384262470907 is actually in microseconds since the epoch if it's meant to be 6081, so you need to divide by 1000 if that's real input.
Note that epochconverter.com doesn't even handle that value - it only allows you to enter 129732384262470 which it then treats as milliseconds since the epoch.
You need to multiply by 1000 if your data is seconds since the epoch. Basically all you need to know is that Java expects milliseconds since the epoch; the rest should be plain sailing, assuming you know what your input data actually means.
If you could provide your real data, and what it's meant to represent, it's probably going to be easy to fix your problems.
If you look carefully, epochconverter.com truncated that number because it was too long for the entry field.
I suggest you print the current value of System.currentMillis() to see what approximate range a "current" epoch-based timestamp has, and re-scale your input number to match. I think you'll probably have to divide by 1000.
In fact, looking closer, if you divide by 10,000, you get 1297323842624, which comes out to a date in 2011. So it's not at all clear what units the number you've given are in.