0

I am working on an application that receives alerts from a server. While processing the alerts, I calculate the last time the an alert was sent by doing the following:

TimeSpan? alertDiffTimespan = DateTime.UtcNow - serverEventInfo.lastAlert

An accurate timespan is important because it allows me to figure out whether a server is active or not.

As of late, I noticed that sometimes serverEventInfo.lastAlert is correct (i.e. being formatted as DateTime.UtcNow) and other times it is an hour ahead/behind the current time (i.e. DateTime.Now). I have tried the following:

TimeSpan? alertDiffTimeSpan = DateTime.UtcNow - serverEventInfo.lastAlert.Value.ToUniversalTime()

but then it means that all the values coming in that are set as DateTime.UtcNow are formatted incorrectly but the ones set as DateTime.Now are correct.

I have tried determining the DateTime.Kind as well, however it keeps flagging as Unspecified each time, so no distinction.

Is there anything I can do to standardise the incoming DateTime values within my application so that no matter whether a UtcNow or a Now value comes in, I can still process it correctly and get a correct alertDiffTimeSpan?

The dates are in format {0:MM/dd/yyyy hh:mm:ss tt} and set as follows String.Format("{0:MM/dd/yyyy hh:mm:ss tt}", DateTime.Now) or String.Format("{0:MM/dd/yyyy hh:mm:ss tt}", DateTime.UtcNow) on the server.

methuselah
  • 12,766
  • 47
  • 165
  • 315
  • 2
    What format are you receiving the datetimes in? If they don't specify whether they're UTC or not.. there's no way you can guess it by yourself. – Rob May 17 '17 at 06:09
  • https://xkcd.com/1179/ is the only acceptable answer... (But it is very hard to see where your problems are coming from as post somewhat lack information) – Alexei Levenkov May 17 '17 at 06:09
  • `DateTime.Now` != `DateTime.Utc(Now)`. The former is adjusted to local time (based from machine's regional settings), where the latter uses ISO 8601 format. The safest way to deal user inputs with different timezone is converting to ISO format first, then display it as local one. – Tetsuya Yamamoto May 17 '17 at 06:15
  • 2
    If it's only one server and you know exactly which time zone it runs, you *might* get away with two checks. Once treating it as UTC and once treating it as local server time. But that's pretty bad. If you have any control over the server at all, figure out, why it's sending UTC/local seemingly willynilly and make sure that it *always* sends UTC. – Corak May 17 '17 at 06:16
  • @AlexeiLevenkov - I don't think the submitted format is the problem. The problem seems to be that the submitted `DateTime` switches between being UTC and (server) local time with no indication what it is exactly. – Corak May 17 '17 at 06:20
  • @Rob they are set in the standard DateTime format, unfortunately the issue I have is that o can't figure out whether they are coming in as Utc or Now. – methuselah May 17 '17 at 06:22
  • 1
    @methuselah What do you mean by the standard DateTime format? There are many 'standard' formats. Does it include an offset? – Rob May 17 '17 at 06:23
  • @Corak there are multiple servers all sending out alerts, the format is okay but sometimes I have noticed they come in as Local or Utc which makes it difficult to process – methuselah May 17 '17 at 06:23
  • @Rob a standard date time string – methuselah May 17 '17 at 06:29
  • @methuselah - then again: best way would be to make sure every server sends UTC. Or at least make the servers send their UTC-offset, too. Worst (imho): keep a list of servers that don't send UTC and have their offset... – Corak May 17 '17 at 06:29
  • 1
    @methuselah I think you're missing what I'm asking. Can you *show* us this string and format? Saying it's a standard string means nothing. There are many standard formats. Some include offsets, some do not. – Rob May 17 '17 at 06:30
  • @methuselah - "the great thing about standards is: there are so many to choose from". So for example is it: `"yyyy-MM-dd HH:mm:ss"`? – Corak May 17 '17 at 06:31
  • @Corak I don't have this information on me at the moment. But I now understand exactly what you are talking about. When I get it, I will add it to the question. – methuselah May 17 '17 at 07:10
  • 1
    If the servers are sending local times without time zone information, you basically don't have enough information. You need to fix that at the source. – Jon Skeet May 17 '17 at 07:16
  • @Corak please see update to question – methuselah May 17 '17 at 11:58
  • @methuselah - Okay, so if you can change it on the server, you should again only ever use `UtcNow`, never just `Now` (at least when communicating with the "outside"). If you can at least change the format string, put some `z`s in there, that way you'll at least get the time zone offset (see [Custom Date and Time Format Strings](https://msdn.microsoft.com/library/8kb3ddd4.aspx) for more information). Either way, you *need* to change something on those servers. – Corak May 17 '17 at 12:10
  • Also note that `"MM/dd/yyyy"` is culture dependent! `"/"` as the date separator could be different in different cultures. For example in `de-DE` you'd get `05.17.2017` from that. So I'd strongly advise, you use `"yyyy-MM-dd"`, which is the ISO standard for dates. (which was also the point of Alexei) -- Also, if you use `"HH"` instead of `"hh"`, you can remove the `"tt"`. – Corak May 17 '17 at 12:10
  • @Corak based on comments OP tries to guess correct value instead of relying on full ISO8601 format with timezone... So proper recommendation about format should be "o" (or http://stackoverflow.com/questions/114983/given-a-datetime-object-how-do-i-get-an-iso-8601-date-in-string-format) – Alexei Levenkov May 17 '17 at 15:20
  • @AlexeiLevenkov - ah, you are of course correct about using `"o"`. I only ever use custom formats (when needed) to be in full control so I tend to forget these useful standard formats. – Corak May 17 '17 at 16:07

1 Answers1

3

You can't guess correct value of DateTime if you don't have time zone information specified in some way. It sounds like you servers may "randomly" pick between local (possibly multiple time zones) and UTC and you have no way to know which one is which.

Fixes:

  • align all servers to return UTC time and continue using formats that don't specify timezone. When reading server value specify Utc at the end: DateTime.SpecifyKind(parsedDateTime, DateTimeKind.Utc)
  • require time zone information in serialized data. Preferably use full ISO8601 like "2017-05-17T08:27:27.0314698Z" (dateTime.ToString("o"), more info - Given a DateTime object, how do I get an ISO 8601 date in string format?, or if you like pictures more - https://xkcd.com/1179/)

Do not use any formats that are culture-specific (like default ToString()) in serialized data unless you have 100% confidence that all servers configured with identical locale settings and your parsing code always specifies the same culture when reading values. Again ISO8601 is safer choice.

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179