Java File last modified in default timezone? - java

I'd like to get the last modified date in my computers timezone (same that I see in the windows file explorer)
System.out.println(myFile.lastModified()); // I get UTC

From documentation myFile.lastModified()
Returns: A long value representing the time the file was last modified, measured in milliseconds since the epoch (00:00:00 GMT,
January 1, 1970), or 0L if the file does not exist or if an I/O error
occurs
So you need to convert it to a date, if you are using Java 8+, you can use java.time API like so :
LocalDateTime date = LocalDateTime.ofInstant(
Instant.ofEpochMilli(myFile.lastModified()), ZoneId.systemDefault()
);
System.out.println(date);//example result : 2018-06-06T15:05:19.113
If you want more precision you can use :
File myFile = new File("pathname");
Long timeMs = myFile.lastModified();
if (timeMs != 0) {
LocalDateTime date = LocalDateTime.ofInstant(
Instant.ofEpochMilli(myFile.lastModified()), ZoneId.systemDefault()
);
System.out.println(date);
}else{
System.out.println("File not exist!");
}

You can simply use a ZonedDateTime object and apply the system's default time offset to it.
ZonedDateTime zt = ZonedDateTime.ofInstant(Instant.ofEpochMilli(myFile.lastModified()), ZoneId.systemDefault());
You can then simply print out this object or work further with it.

Related

Display time without converting to local time zone

I have an API that gives me this JSON response
{
"time": "2020-05-25T05:18:02.279842+01:00",
"timezone_name": "LMT",
"timezone": "Europe/London"
}
Now, I have 2 problems.
Converting the time to date object. I used SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ") but, gives me parse exception. I think it’s because of milliseconds which is in 6 digits SSSSSS(279842). So I converted this 2020-05-25T05:18:02.279842+01:00" to 2020-05-25T05:18:02.279+01:00" which worked. I’m not satisfied with string manipulation.
When I format the date from above, I see the time in my local time zone not the London time. I think I have to set the time zone for the date object which is given in the time zone.
Overall, I just want to neatly parse the txt to data object and show the time in given time zone.
Appreciate your inputs.
I ended up with this solution.
private fun format(str: String): String {
// expected input format "2020-05-24T08:19:40.807726-05:00"
try {
val slits = str.split(".")
val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
inputFormat.timeZone = TimeZone.getTimeZone(timezone/*"Europe/London"*/)
val outputFormat = SimpleDateFormat("h:mm a")
outputFormat.timeZone = inputFormat.timeZone
return outputFormat.format(inputFormat.parse(slits[0])!!)
} catch (e: Exception) {
Log.e(MWLocationInfo::class.java.simpleName, e.stackTrace.toString());
}
return "-"
}
About 2 - SimpleDateFormat always returns time in local time of JVM, so you need to set timezone to SimpleDateFormat as
TimeZone timeZone = TimeZone.getTimeZone("Europe/London");
simpleDateFormat.setTimeZone(timeZone);
SimpleDateFormat is now legacy, think of using java.time API (introduced in java 8). Using java.time API -
ZonedDateTime zonedDateTime = ZonedDateTime.parse("2020-05-25T05:18:02.279842+01:00[Europe/London]");

My question is about converting epoch millisecond from date in groovy

I am generating epoch timestamp in milliseconds with the following code and it works (verified with https://www.epochconverter.com/). However, when we are setting timezone with JVM option -Duser.timezone=America/Toronto then for some historical dates time offset is differ by one hour. i.e Date=1950-11-19 (yyyy-MM-dd) correct epoch milliseconds -603313200000 (Sunday, November 19, 1950 12:00:00 AM GMT-05:00) but when timezone is set with JVM options value is -603316800000 and Epoch converted shows Saturday, November 18, 1950 11:00:00 PM GMT-05:00. I have used joda time lib with JDK 10
def static Long getEpochTimeStampInMilliSeconds(String simpleDate, String dateFormat) {
Long retVal = null
try {
org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(dateFormat)
DateTimeZone dtz2 = DateTimeZone.forID("America/Toronto")
DateTime parsedDateTime = DateTime.parse(simpleDate, fmt).withZone(dtz2)
retVal = parsedDateTime.getMillis()
} catch (Exception e) {
retVal = null
}
return retVal
}
date format is : "yyyy-MM-dd"
You need to parse with the correct time zone, so instead of calling dateTime.withZone(...) after parsing is done, you need to call dateTimeFormatter.withZone(...) before parsing with the formatter.
If the default time zone, as set by the user.timezone system property is America/Toronto, then the parsed DateTime value is already in that time zone, and dateTime.withZone(...) will do nothing.
If the default time zone is something else, then the parsed DateTime value is in that time zone, which would be a different UTC epoch millisecond value. Calling dateTime.withZone(...) will change the time zone, and hence the time value, but will not change the UTC epoch millisecond value.
def dtz2 = org.joda.time.DateTimeZone.forID("America/Toronto")
def fmt = org.joda.time.format.DateTimeFormat.forPattern(dateFormat).withZone(dtz2)
retVal = org.joda.time.DateTime.parse(simpleDate, fmt).getMillis()
UPDATE
From comment:
I am receiving -603316800000 for 1950-11-19 for all scenario but correct value is -603313200000
Lets test which value is correct, using Java-Time API:
ZoneId zone = ZoneId.of("America/Toronto");
System.out.println(Instant.ofEpochMilli(-603316800000L));
System.out.println(Instant.ofEpochMilli(-603316800000L).atZone(zone));
System.out.println(Instant.ofEpochMilli(-603313200000L));
System.out.println(Instant.ofEpochMilli(-603313200000L).atZone(zone));
Output
1950-11-19T04:00:00Z
1950-11-19T00:00-04:00[America/Toronto] ⬅ Correct value
1950-11-19T05:00:00Z
1950-11-19T01:00-04:00[America/Toronto]
As you can see, the value you get (-603316800000) is the correct value for 1950-11-19 at midnight, Toronto time.
You get offset -04:00 for Toronto, because in 1950, DST lasted until Sun, Nov 26 at 2:00 am (see https://www.timeanddate.com/time/zone/canada/toronto), so the offset is correct for Eastern Daylight Time (EDT).
Don't know why you think -603313200000 is the correct value, but it is not.

How do I touch a folder with current time using set last modified date & time?

I'm trying to update the last modified date of a specific folder, here's what I've got:
public void touchFolder(){
File folderToTest = new File("C:\\Temp");
SimpleDateFormat dateFormatUtc = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
dateFormatUtc.setTimeZone(TimeZone.getTimeZone("UTC"));
String newTime = dateFormatUtc.format(new Date());
folderToTest.setLastModified(Long.parseLong(newTime));
}
I am just putting this code in a test case so don't worry about calling this method etc.
I'm getting errors with the parsing that date format as a long, what's the format used in setting the last modified date & time?
This is an example from the documentation, using java.nio.file.Files:
Path path = ...
FileTime now = FileTime.fromMillis(System.currentTimeMillis());
Files.setLastModifiedTime(path, now);
I think you should just do folderToTest.setLastModified(System.currentTimeMillis());
In your code newTime is a formatted date 2018-12-19 15:21:31 which can't be parsed to Long. What you want to do is supply the time in milliseconds e.g.:
Date d = new Date();
file.setLastModified(d.getTime());
As per File.setLastModified() method javadoc:
time - The new last-modified time, measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)

Time parsing issue on Android

I am getting a parse exception when trying to parse the time string 02:22 p.m..
I have the following conversion function:
public static long convertdatetotimestamp(String datestring, String newdateformat, String olddateformat){
SimpleDateFormat originalFormat = new SimpleDateFormat(olddateformat,Locale.ROOT);
SimpleDateFormat targetFormat = new SimpleDateFormat(newdateformat,Locale.ROOT);
Date date = null;
try {
date = originalFormat.parse(datestring);
String formattedDate = targetFormat.format(date);
Date parsedDate = targetFormat.parse(formattedDate);
long nowMilliseconds = parsedDate.getTime();
return nowMilliseconds;
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
The method is called in another activity with a time format "02:22 p.m.". olddateformat and newdateformat are the same: hh:mm a.
It causes following error in log:
java.text.ParseException: Unparseable date: "02:22 p.m." (at offset 6)
How to resolve this issue? Time is in exactly above mentioned format.
It so happens that a.m. and p.m. are called just this in Gaelic locale. At least on my Java 8. I am far from sure that it will be the case on (all) Android phones, but you may do some experiments with it.
String datestring = "02:22 p.m.";
Locale parseLocale = Locale.forLanguageTag("ga");
DateTimeFormatter originalFormat = DateTimeFormatter.ofPattern("hh:mm a", parseLocale);
System.out.println(LocalTime.parse(datestring, originalFormat));
This prints
14:22
As Hugo so warmly and rightly recommends is his answer, I am using the modern Java date and time API, so you will need ThreeTenABP for the above code. See How to use ThreeTenABP in Android Project. Alternatively you may want to try the same locale with your otherwise outdated SimpleDateFormat.
US Spanish locale shows the same behaviour on my Java 8, so you may try that too: Locale.forLanguageTag("es-US").
I believe that SimpleDateFormat can't be customized to parse the p.m. part (it only recognizes AM or PM).
So one alternative is to remove the dots:
String time = "02:22 p.m.";
SimpleDateFormat format = new SimpleDateFormat("hh:mm a", Locale.ROOT);
date = format.parse(time.replaceAll("\\.", ""));
One detail: to get the nowMilliseconds value, you need all the date fields (day/month/year) and a timezone. As those fields are not in the input String, SimpleDateFormat sets them to January 1st of 1970 (and also set the seconds and milliseconds to zero), and use the system's default timezone.
I'm not sure if this behaviour of getting January 1970 is consistent among all Java versions, which is another problem because you can get different values depending on the environment/device the code is running. Actually, you might have a different result anyway because it uses the system's default timezone and this can vary among different environments.
If I run this code in my machine, it uses my system's default timezone (America/Sao_Paulo), and the result is 62520000. But if I change the timezone to another (let's say, Asia/Kolkata), the result is 31920000. You must be aware of this variation and check if that's what you really need.
Another detail is that, if olddateformat and newdateformat are the same, there's no need to create 2 different formatters.
Java's new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
In Android you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. You'll also need the ThreeTenABP (more on how to use it here).
All the relevant classes are in the org.threeten.bp package.
With this new API, you can customize the text that corresponds to AM/PM using a org.threeten.bp.format.DateTimeFormatterBuilder (so no need to remove the dots manually). And there are specific classes to each case - in this case, the input has only the time fields (hour and minutes), so I'm going to use the org.threeten.bp.LocalTime class (which represents only a time - hour/minute/second/nanosecond - without a date):
String time = "02:22 p.m.";
// map AM and PM values to strings "a.m." and "p.m."
Map<Long, String> map = new HashMap<Long, String>();
map.put(0L, "a.m.");
map.put(1L, "p.m.");
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// hour and minute
.appendPattern("hh:mm ")
// use custom values for AM/PM
.appendText(ChronoField.AMPM_OF_DAY, map)
// create formatter
.toFormatter(Locale.ROOT);
// parse the time
LocalTime parsedTime = LocalTime.parse(time, fmt);
The parsedTime variable will contain the values corresponding to 02:22 PM (and only this value, it has no date fields (day/month/year) nor a timezone).
To get the milliseconds value (number of milliseconds since 1970-01-01T00:00Z), you also need a date (day/month/year) and a timezone. As I said previously, those fields can affect the final value.
In the old API, SimpleDateFormat tries to be "smart" and sets default values for those fields (January 1st of 1970 in the system's default timezone), but the new API is more strict about that and you must tell explicity what date and timezone you want.
In this example, I'm using the Asia/Kolkata timezone but you can change it according to your needs (more on that below):
import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
// timezone for Asia/Kolkata
ZoneId zone = ZoneId.of("Asia/Kolkata");
// current date in Kolkata timezone
LocalDate now = LocalDate.now(zone);
// get the parsed time at the specified date, at the specified zone
ZonedDateTime zdt = parsedTime.atDate(now).atZone(zone);
// get the millis value
long millis = zdt.toInstant().toEpochMilli();
If you want a specific date instead of the current date, you can use LocalDate.of(2017, 5, 20) - this will get May 20th, 2017, for example. With this, you can set the code above to the date and timezone you need.
Note that the API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Asia/Kolkata).
Avoid using the 3-letter abbreviations (like IST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
If you want to emulate exactly what SimpleDateFormat does, you can use LocalDate.of(1970, 1, 1) and use the default timezone with ZoneId.systemDefault() - but this is not recommended, because the system's default can be changed without notice, even at runtime. It's better to explicit what timezone you're using.
Or you can create a formatter that always sets default values for the date (using the org.threeten.bp.temporal.ChronoField class) and always uses the same timezone. So you can parse it directly to a org.threeten.bp.Instant and get the millis value:
String time = "02:22 p.m.";
ZoneId zone = ZoneId.of("Asia/Kolkata");
DateTimeFormatter fmt2 = new DateTimeFormatterBuilder()
// hour and minute
.appendPattern("hh:mm ")
// use custom values for AM/PM (use the same map from previous example)
.appendText(ChronoField.AMPM_OF_DAY, map)
// default value for day: 1
.parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
// default value for month: January
.parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
// default value for year: 1970
.parseDefaulting(ChronoField.YEAR, 1970)
// create formatter at my specific timezone
.toFormatter(Locale.ROOT).withZone(zone);
// get the millis value
long millis = Instant.from(fmt2.parse(time)).toEpochMilli();
Following changes that i've made works fine for me.
public static long convertdatetotimestamp(String datestring, String newdateformat, String olddateformat){
DateFormat originalFormat = new SimpleDateFormat(olddateformat,Locale.ENGLISH);
DateFormat targetFormat = new
SimpleDateFormat(newdateformat,Locale.ENGLISH);
Date date = null;
try {
date = originalFormat.parse(datestring.replaceAll("\\.", ""));
String formattedDate = targetFormat.format(date);
Date parsedDate = targetFormat.parse(formattedDate);
long nowMilliseconds = parsedDate.getTime();
return nowMilliseconds;
} catch (ParseException e) {
e.printStackTrace();
return 0;
}
}
Locale.ENGLISH you can use your locale, english solved my issue. Reference.
Thanks for responses and references.

How can I create a Java 8 LocalDate from a long Epoch time in Milliseconds?

I have an external API that returns me dates as longs, represented as milliseconds since the beginning of the Epoch.
With the old style Java API, I would simply construct a Date from it with
Date myDate = new Date(startDateLong)
What is the equivalent in Java 8's LocalDate/LocalDateTime classes?
I am interested in converting the point in time represented by the long to a LocalDate in my current local timezone.
If you have the milliseconds since the Epoch and want to convert them to a local date using the current local timezone, you can use Instant.ofEpochMilli(long epochMilli)
LocalDate date =
Instant.ofEpochMilli(longValue).atZone(ZoneId.systemDefault()).toLocalDate();
but keep in mind that even the system’s default time zone may change, thus the same long value may produce different result in subsequent runs, even on the same machine.
Further, keep in mind that LocalDate, unlike java.util.Date, really represents a date, not a date and time.
Otherwise, you may use a LocalDateTime:
LocalDateTime date =
LocalDateTime.ofInstant(Instant.ofEpochMilli(longValue), ZoneId.systemDefault());
You can start with Instant.ofEpochMilli(long):
LocalDate date =
Instant.ofEpochMilli(startDateLong)
.atZone(ZoneId.systemDefault())
.toLocalDate();
I think I have a better answer.
new Timestamp(longEpochTime).toLocalDateTime();
Timezones and stuff aside, a very simple alternative to new Date(startDateLong) could be LocalDate.ofEpochDay(startDateLong / 86400000L)
A simple version based on #Michael Piefel answer:
LocalDate myDate = LocalDate.ofEpochDay(Duration.ofMillis(epochMillis).toDays());
replace now.getTime() with your long value.
//GET UTC time for current date
Date now= new Date();
//LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
LocalDate localDate = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDate();
DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));
I have tested this alternative solution for LocalDateTime:
public static LocalDateTime increaseByMillis(final LocalDateTime ldt, final long millis)
{
return LocalDateTime.ofInstant(Instant.ofEpochMilli(ldt.toInstant(ZoneOffset.UTC).toEpochMilli()+millis), ZoneId.of(ZoneOffset.UTC.getId()));
}
Test:
LocalDateTime test = LocalDateTime.now();
LocalDateTime increased = MyUtilsAbc.increaseByMillis(test, 1000);
Assert.assertEquals("Increase of LocalDateTime not working (anymore)!", test.toEpochSecond(ZoneOffset.UTC) +1, increased.toEpochSecond(ZoneOffset.UTC));
In a specific case where your epoch seconds timestamp comes from SQL or is related to SQL somehow, you can obtain it like this:
long startDateLong = <...>
LocalDate theDate = new java.sql.Date(startDateLong).toLocalDate();

Categories

Resources