After deploying to production environemnt my code broke, and after quite a bit of bug chasing, I discovered that JodaTime was handling de/serialization differently in production than in dev environement. Apparently significantly, the production server is on another time zone.
Deserialization and serialization on development:
scala> val input = "2013-09-07T17:11:03.117+03:00"
input: String = 2013-09-07T17:11:03.117+03:00
scala> val thisIsDev = new DateTime(input).toString()
thisIsDev: String = 2013-09-07T17:11:03.117+03:00
scala> input == thisIsDev
res3: Boolean = true
Notice the +03:00 at the end of the ISO8601 string, both initially and after reserialization. Now this is what happens in production, which is on +0 time zone:
scala> val sameInput = "2013-09-07T17:11:03.117+03:00"
sameInput: String = 2013-09-07T17:11:03.117+03:00
scala> val thisIsProd = new DateTime(sameInput).toString()
thisIsProd: String = 2013-09-07T14:11:03.117Z
scala> sameInput == thisIsProduction
res1: Boolean = false
As you can see, +03:00 was absolved and the date string's format changed time zones.
Is this a solved problem? Suggestions?
Edit:
To clarify, the problem with this is that if I serialize, change time zones (go to a different server for example), then deserialize and reserialize, I end up with a different string than what I started with. This is why my production broke, but my tests didn't. Took me a while to figure this out.
Note: These ISO8601 strings are used on a CouchDb server that sorts them alphanumerically, that's why I can't use JodaTime methods for comparison.
Edit 2:
Ideally the answer would suggest how to deserialize an ISO8601 string into DateTime object without loosing the time zone information (on different time zones).
Edit 2.1: I opened a relevant question and got the solution I needed here.
Given your edited question, the simplest answer is to force every datetime to be in the same timezone, so for example
scala> new DateTime("2013-09-07T17:11:03.117+03:00").withZone(DateTimeZone.UTC)
res1: org.joda.time.DateTime = 2013-09-07T14:11:03.117Z
scala> new DateTime("2013-09-07T14:11:03.117Z").withZone(DateTimeZone.UTC)
res2: org.joda.time.DateTime = 2013-09-07T14:11:03.117Z
However be aware that in this situation you are losing information i.e. the timezone in which the date resides. If you are using your date for internal purposes (e.g. finding new items) then this doesn't matter so much, bit if you are sending your data back to users then you need to find another solution.
Related
I have two different formats for data and I am trying to have a common format.
Format A
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"
Sample time:
2020-09-10T22:40:58.807+00:00
Format B
"yyyy-MM-dd'T'HH:mm:ss.SSSSSSSX"
Sample time:
2020-07-23T02:46:04.0978382Z
I am trying to merge them into one common format and eventually use them for a SQL Dataframe with type Timestamp. I have been using SimpleDateFormat for format A, and for Format B I cannot parse with SimpleDateFormat as it doesn't support Nanoseconds, so instead have been using
val inFormat = DateTimeFormatter.ofPattern(timestampFormat)
val localDatetime = LocalDateTime.parse(timestampString, inFormat)
Timestamp.valueOf(localDatetime) // converting Datetime to timestamp
After using the above my Format B sample time is 2020-07-23 02:46:04.0978382 While format A using SimpleDateFormat is 2020-09-10 22:40:58.807
How can I create a common format for both A and B to be later used into a SQL table? My goal is for whats in format A matches what is in format B(granularity too).
Something that I am trying is using OffsetDateTime to convert both formats. With OffSetDateTime I will
import java.time.OffsetDateTime
val odt = OffsetDateTime.parse(2020-07-23T02:46:04.0978382Z)
println(odt)
In this case, seems like I would truncate offsetDatetime? Is this a good approach?
Thanks
You haven’t got two different formats. What you call format A and format B are both variants of ISO 8601 format, the international standard. OffsetDateTime parses the most common ISO 8601 variants as its default, that is, without any explicit formatter. Also both of your variants.
OffsetDateTime dateTimeA = OffsetDateTime.parse("2020-09-10T22:40:58.807+00:00");
System.out.println(dateTimeA);
OffsetDateTime dateTimeB = OffsetDateTime.parse("2020-07-23T02:46:04.0978382Z");
System.out.println(dateTimeB);
Output:
2020-09-10T22:40:58.807Z
2020-07-23T02:46:04.097838200Z
You also notice that no values have been truncated.
You probably don’t need to convert to a java.sql.Timestamp. That’s good because the Timestamp class is a hack on top of the already poorly designed java.util.Date class, and both those classes are long outdated. Assuming that you need a timestamp with time zone in SQL (recommended for timestamps), since JDBC 4.2 pass your OffsetDateTime to SQL. An example:
OffsetDateTime dateTimeA = OffsetDateTime.parse("2020-09-10T22:40:58.807+00:00");
PreparedStatement insertStmt = yourDatabaseConnection.prepareStatement(
"insert into your_table(your_timestamp_with_time_zone_column) values (?)");
insertStmt.setObject(1, dateTimeA);
int rowsInserted = insertStmt.executeUpdate();
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
My answer to a related question: Getting the date from a ResultSet for use with java.time classes
You don't need a "common" format.
You have 2 options:
You can detect with regex what format your current input has.
Like:
def parse(inputString: String): Timestamp {
if(isFormatA(inputString))
parseFormatA(inputString)
else
parseFromatB(inputString)
}
You can improve it with regex pattern matching.
You can sequentially try both formats with exception handling or library that will return option.
Like:
def parse(inputString: String): Timestamp {
Try(parseFormatA(inputString))
.orElse(Try(parseFormatB(inputString)))
.get
}
how to convert milliseconds to timestamp in kotlin.
time in milliseconds : 1575959745000 to format: dd/MM/yyyy HH:MM:ss
EDIT: now, there is the kotlinx-datetime library
There is no pure Kotlin support for dates at the moment, only durations.
You will have to rely on the target platform's facilities for date/time parsing and formatting.
Note that, whatever platform you're targeting, it doesn't really make sense to convert a millisecond epoch to a formatted date without defining the timezone.
If you're targeting the JVM, then you can use the java.time API this way:
// define once somewhere in order to reuse it
val formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
// JVM representation of a millisecond epoch absolute instant
val instant = Instant.ofEpochMilli(1575959745000L)
// Adding the timezone information to be able to format it (change accordingly)
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
println(formatter.format(date)) // 10/12/2019 06:35:45
If you're targeting JavaScript, things get trickier. You can do the following to use some sort of default time zone, and some close-enough format (defined by the locale "en-gb"):
val date = Date(1575959745000)
println(date.toLocaleString("en-gb")) // 10/12/2019, 07:35:45
You have ways to specify the timezone according the standard JS API for Date.toLocaleString(). But I haven't dug much into the details.
As for native, I have no idea.
I am working on a news website and I am saving all dates in the database in UTC. Then, depending on the browser/machine location, I want to display the date/time correspondingly (Convert from UTC to the Local time of the machine/browser).
First of all, I would like to know if I am doing this the way it should be done or not (UTC dates in the database).
Second, I wonder why isn't it that straightforward to do so in VB.NET? Below are the approaches I tried but none worked as needed:
Approach 1:
TimeZoneInfo.ConvertTimeFromUtC
This kept returning the server time and not the client/machine time.
Approach 2:
Dim TimeZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Middle East Standard Time")
Dim Dated As DateTime = TimeZoneInfo.ConvertTimeFromUtC(TempDate, TimeZone)
This worked but not as intended. This converted the UTC date/time in the database to the Middle East Time Zone but any user from any other place in the world will only see the date/time in Middle East Time Zone and not in the actual timezone of his place. Also, I am not sure if the conversion considers DayLightSaving or not.
Approach 3:
I tried to fix this using JavaScript. I created a cookie that saves the offset from UTC and tried handling the offset in VB.NET and do the conversion.
<script>
function setCookie(cname, cvalue, exdays) {
var d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getTimeOffset() {
var offset = new Date().getTimezoneOffset();
setCookie("_tz", offset);
}
</script>
JavaScripts returns the correct Offset and I am saving this offset in a cookie. Since JavaScript launches after Page_Load, I am calling the JavaScript function getTimeOffset() on Page_Init:
ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "getTimeOffset();", True)
The cookie is being created before the page is rendered and the offset stored in the cookie is correct (This is what I actually want!). The problem here is on the first load. VB.NET reads the cookie value as empty string on the first load. On the second Page_Load onwards, VB.NET reads the cookie value and does the conversion correctly.
Approach 4
Tried to get the offset using all the examples in this fiddle but the offset is always 0 which is wrong.
Summary
I wonder if there is any function I missed in VB.NET to avoid all that hassle. Shouldn't it be an easy task to convert date/time from UTC to Local?
Please let me know if there is anything I am doing wrong or if there is a better alternative.
Your back-end code doesn't know anything about the time zone of the browser. It doesn't matter what language you are using, only the browser will know anything about the user's time zone.
When .Net code (regardless of VB or C#) refers to "local", it means the local time zone of where that code is running. In other words, in an ASP.Net web application, that's the local time zone of your server, not of the user. Generally speaking, the server's local time zone is usually irrelevant.
To achieve your goal, break the problem up into two parts.
Get the user's time zone in the browser, send it to the server.
Convert time on the server, using the time zone passed in.
For step 1, read this answer I posted to a different question. Note that the output will be an IANA time zone identifier. Do not pass a numeric offset, as it does not carry enough information to properly convert different points in time (consider daylight saving time, and other anomalies with time zones).
For step 2, you'll need to choose between one of these approaches:
You can use the IANA time zone identifier natively with TimeZoneInfo if you're running .NET Core on a non-Windows OS, or with the Noda Time library on any platform.
You can convert the IANA time zone identifier to a Windows time zone identifier using my TimeZoneConverter library, and then you can use the result with the TimeZoneInfo class on Windows.
One little thing: You used TimeZoneInfo.ConvertTimeToUtc, where I think you meant TimeZoneInfo.ConvertTimeFromUtc. Be careful of the directionality of the conversions.
I'll also point out that there's an alternative approach, which is to pass the UTC timestamp all the way down to the browser, and just convert from UTC to local time in JavaScript. Then you don't need to do any time zone detection at all.
I have an app where I set time zones for various cities around the globe. I have no problem doing this and it works great. When the app first loads, it finds your current location (lat & long) and sets the time zone using the device default time zone. I need to return the default time zone in a string, so I can display it. I don't want "GMT" or "EDT", I would like it in the format of "America/New_York" or 'Europe/London". Any ideas?
It sounds like you want this:
NSString *timeZoneName = [[NSTimeZone localTimeZone] name];
That returns "America/New_York" for me, here in the EST time zone.
Or given any NSTimeZone *tz you can get its [tz name], which is the conventional name you are looking for (e.g. "Asia/Tokyo" or "Europe/London".
Look at +[NSTimeZone knownTimeZoneName] for a list of possible names.
I hope that helps.
I don't think there is an object that automatically correlates the time zone to a physical place.
I see you've tagged this objective-c, but in C# you could do something simple like this:
public Enum TimeZone
{
[Description("New York")]
EDT,
[Description("Los Angeles")]
PST
}
public static string GetDescription(Enum value)
{
FieldInfo fi= value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
return (attributes.Length>0)?attributes[0].Description:value.ToString();
}
i'm not sure how easily portable this is to objective-c, and it does require using the reflection library in C#.
Well, you're making the assumption that EDT is the same time zone as America/New_York. It isn't. :) Yes, they're the same UTC offset, but as far as your system is concerned, they are defined independently. There's no strong association between them that Cocoa knows about.
As well, if the user gives you EDT, do you return New_York? Toronto? Panama? There's not a 1:1 correspondence. Oh, and: EDT isn't even unique to a single UTC offset. Australian Eastern Daylight Time is also abbreviated EDT, I'm told by the Cocoa docs.
There is a [NSTimeZone abbreviationDictionary] map between abbreviations and long names, but again, they're arbitrarily chosen when there's more than one association (such as New York and Panama.)
What is it you're trying to accomplish in a broader sense? What's your goal? Tell us and we may be able to suggest an alternate way to achieve it. :)
Does anyone know of a way to declare a date constant that is compatible with international dates?
I've tried:
' not international compatible
public const ADate as Date = #12/31/04#
' breaking change if you have an optional parameter that defaults to this value
' because it isnt constant.
public shared readonly ADate As New Date(12, 31, 04)
If you look at the IL generated by the statement
public const ADate as Date = #12/31/04#
You'll see this:
.field public static initonly valuetype [mscorlib]System.DateTime ADate
.custom instance void [mscorlib]System.Runtime.CompilerServices.DateTimeConstantAttribute::.ctor(int64) = ( 01 00 00 C0 2F CE E2 BC C6 08 00 00 )
Notice that the DateTimeConstantAttribute is being initialized with a constructor that takes an int64 tick count. Since this tick count is being determined at complile time, it seems unlikely that any localization is coming into play when this value is initialized at runtime. My guess is that the error is with some other date handling in your code, not the const initialization.
According to the Microsoft documentation,
"You must enclose a Date literal within number signs (# #). You must specify the date value in the format M/d/yyyy, for example #5/31/1993#. This requirement is independent of your locale and your computer's date and time format settings."
Are you saying that this is not correct and the parsing is affected by the current locale?
Edit: Did you try with a 4-digit year?
Once you have data into Date objects in VB, you don't have to worry about globalization until you compare something to it or try to export it.
This is fine:
Dim FirstDate as Date = Date.UtcNow() 'or this: = NewDate (2008,09,10)'
Dim SecondDate as Date
SecondDate = FirstDate.AddDays(1)
This pulls in the globalization rules and prints in the current thread's culture format:
HeaderLabel.Text = SecondDate.ToString()
This is bad:
Dim BadDate as Date = CDate("2/20/2000")
Actually--even that is OK if you force CDate in that case to use the right culture (InvariantCulture):
Dim OkButBadPracticeDate as Date = CDate("2/20/2000", CultureInfo.InvariantCulture)
If you want to force everything to a particular culture, you need to set the executing thread culture and UI culture to the desired culture (en-US, invariant, etc.).
Make sure you aren't doing any work with dates as strings--make sure they are actual Date objects!
Ok right, I understand more where you are coming from..
How about:
Create a static method that returns the date constant. This overcomes the international issue since it is returned as the specific DateTime value.
Now I remember optional params from my VB6 days, but can you not just overload the method? If you are using the overloaded method without the date, just pull it from the static?
EDIT: If you are unsure what I mean and would like a code sample, just comment this post and I will chuck one on.
OK, I am unsure what you are trying to do here:
The code you are posting is NOT .NET, are you trying to port?
DateTime's cannot be declared as constants.
DateTime's are a data type, so once init'ed, the format that they were init'ed from is irrelevant.
If you need a constant value, then just create a method to always return the same DateTime.
For example:
public static DateTime SadDayForAll()
{
return new DateTime(2001, 09, 11);
}
Update
Where the hell are you getting all that from?!
There are differences between C# and VB.NET, and this highlights one of them.
Date is not a .NET data type - DateTime is.
It looks like you can create DateTime constants in VB.NET but there are limitations
The method was there to try and help you, since you cannot create a const from a variable (i.e. optional param). That doesn't even make sense.