C# converting to and from Unix time - 1 day lost - c#

here is the code:
var date = DateTime.Now.Date;
var ms = (long)(date - DateTimeOffset.UnixEpoch).TotalMilliseconds;
var date1 = DateTimeOffset.FromUnixTimeMilliseconds(ms).DateTime.Date;
date is 24th and date1 is 23rd
why dont they match?

Use DateTimeOffset.FromUnixTimeMilliseconds(ms).LocalDateTime.
DateTime.Now has Kind = Local so it is eskewing your UTC offset.
You can see it with:
var kind = DateTime.Now.Date.Kind;
and then you can make a small test with the "kind":
var date = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
var ms = (long)(date - DateTimeOffset.UnixEpoch).TotalMilliseconds;
How much ms is? Depending on winter/summer time and your location, it probably isn't 0.
So your ms includes your UTC offset. Now you have to:
var date1 = DateTimeOffset.FromUnixTimeMilliseconds(ms).LocalDateTime;
and let's hope you are still in the "original" utc offset (so not enough days have passed between the calculation of date and the calculation of date1 for you to switch between winter/summer time)
(if you did everything correctly, you don't really need the .Date after .LocalDateTime, because the date should already be 00:00:00)

Related

C# How to convert date local to UTC with time 00:00:00 and 23:59:59?

I have a stored procedure which returns data between date range. I am sending Start Date and End Date as parameters after converting those dates into UTC. I am facing difficulty due to time span.
For example:
StartDate: 2019-08-05T06:11:02.676Z
EndDate: 2019-08-05T06:11:02.676Z
I can not get data for the day 5th of August.
For that I need datetime format like,
StartDate: 2019-08-05T00:00:00
EndDate: 2019-08-05T23:59:59
Please help me to derive above datetime format.
You can use DateTime.Now.Date() to get only Date and compare only dates.
var dateAndTime = DateTime.Now;
var date = dateAndTime.Date;
Just create two DateTimes objects with the time set, for example:
var now = DateTime.Now();
var startDate = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0);
var endDate = new DateTime(now.Year, now.Month, now.Day, 23, 59, 59);

Change the time forward

I am getting dates from the database and for each date I want to change the time forward starting from the DateTime that was obtained from the database until I get to a given Fixed Time (Y). However, (Y) might be in the next day.
For example if the date from the database is [7/6/2017 5:00:00 AM] and the given Fixed Time is 10:00 PM then I want to get [7/6/2017 10:00:00 PM].
However if the fixed time is 02:00 AM then I want to get [7/7/2017 02:00:00 AM] (notice that the date has increased by one)
Note: The code is running, but I modified the code to make it shorter and make more sense. Thus, there might be syntax or spelling mistakes.
My first solution was something like this:
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
return date + difference;
}
That didn't work as expected when the fixed time is 02:00 AM. The difference becomes negative( it doesn't go around the clock) and the date will be [7/6/2017 02:00:00 AM].
I ended up with the following code
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
if (difference.Hours < 0) {
difference += new TimeSpan(24, 0, 0);
}
return date + difference;
}
I am not sure if my function is logically correct and I feel like I am overthinking it. Also,I am not sure if there's a better way or a built in function that does what I want for me. Basically, I am looking for a correct and an elegant solution.
Thank you very much in advanced.
In this method, I'm using DateTime fixedTime to represent a time. I don't really care about it's Day, Month, and Year values.
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
if (dbTime < cutoff)
return cutoff;
else
{
cutoff = cutoff.AddDays(1);
return cutoff;
}
}
Here's calling it with your provided example input.
var FixedTime10PM = new DateTime(1, 1, 1, 22, 0, 0);
var FixedTime02AM = new DateTime(1, 1, 1, 2, 0, 0);
var dbTime = new DateTime(2018, 6, 20, 5, 0, 0);
var dt1 = GetClosingTime(FixedTime10PM, dbTime);
var dt2 = GetClosingTime(FixedTime02AM, dbTime);
Console.WriteLine(dt1.ToLongDateString() + " " + dt1.ToLongTimeString());
Console.WriteLine(dt2.ToLongDateString() + " " + dt2.ToLongTimeString());
And here's my output:
EDIT:
Simplified method based on suggestions in comments:
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
return dbTime < cutoff ? cutoff : cutoff.AddDays(1);
}
Your logic is almost right but you shouldn't be checking for difference.Hours because there might be a difference in minutes (or even seconds if you changed the format later).
I adjusted your function and changed some variable names to make them easier to follow:
private DateTime SetTimeForward(DateTime originalDate)
{
TimeSpan newTime = DateTime.ParseExact(FixedTime,
"hh:mm tt",
CultureInfo.InvariantCulture).TimeOfDay;
TimeSpan diff = newTime - originalDate.TimeOfDay;
if (diff.Ticks < 0)
diff = diff.Add(new TimeSpan(24, 0, 0));
return originalDate.Add(diff);
}
Some remarks:
If your FixedTime is really fixed, you might want to store it directly as a TimeSpan so you don't have to parse it every time.
If you parse the FixedTime because it's changeable, you might pass it as a second argument instead:
private DateTime SetTimeForward(DateTime originalDate, string fixedTime)
Or:
private DateTime SetTimeForward(DateTime originalDate, TimeSpan newTime)
The current implementation does not change the date value if the newTime is equal to originalDate.TimeOfDay. I.E., If the originalDate is 7/6/2017 2:00 AM and the FixedTime/newTime is 02:00 AM, the returned date will be equal to the originalDate. If that's not your desired behavior, you might change diff.Ticks < 0 to diff.Ticks <= 0.
Slightly different approach:
private DateTime setTimeForeward(DateTime date)
{
var targetTimeOfDay = TimeSpan.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
if (targetTimeOfDay < date.TimeOfDay)
{
date = date.AddDays(1);
}
return date.Date + targetTimeOfDay;
}
I'm getting target time as TimeSpan from the beginning instead of creating DateTime and getting TimeOfDay (which is TimeSpan).
Then I check if the target time of day is lower than time to be modified and if it is I add one day.
I use date.Date + targetTimeOfDay as return value as date.Date will return date with time set to 00:00 and adding target time to it will already set the target hour without calculating the difference.

how to convert universal time to AM and PM?

I converted 2014-08-21 12:00 AM to 2014-08-21T18:30:00.000Z using
ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fffK")
But now i want to reverse it.
How can i convert 2014-08-21T18:30:00.000Z to 2014-08-21 12:00 AM?
Here you go:
var localFormat = "MM-dd-yyyy HH:mm tt";
string universalFormat = "yyyy-MM-dd'T'HH:mm:ss.fffK";
var now = DateTime.Now;
Console.WriteLine(now.ToString(localFormat));
var universal = now.ToUniversalTime().ToString(universalFormat);
Console.WriteLine(universal);
var newNow = Convert.ToDateTime(universal).ToLocalTime().ToString(localFormat);
Console.WriteLine(newNow);
Output:
8/24/2014 11:16 PM
2014-08-25T06:16:45.229Z
8/24/2014 11:16 PM
Last one is a string, just like the universal one, but you may forgo the ToString() conversion and simply format it on demand. Up to you, I simply provide the foundation code.
EDIT:
Per OP's request in the comments:
// Here's one way of converting a string to DateTime.
var date = Convert.ToDateTime("8/24/2014 11:16:45 PM");
// Here's one way of creating DateTime by providing arguments.
var date = new DateTime(2014, 8, 24, 23, 16, 45);
I'd also recommend providing localization as one of the arguments, just to be safe. Once you have those variables, you may do all the same actions as the prior code showcased.
If you want just the date or just the time, simply format your output accordingly:
// If you want strings.
date.ToString("MM-dd-yyyy");
date.ToSTring("HH:mm:ss");
// If you want DateTime and TimeSpan
date.Date();
date.TimeOfDay();
I just did this in LINQPad:
var dt = DateTime.Parse("2014-08-21 12:00 AM")
.ToUniversalTime()
.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
var dtReverse = DateTime.Parse("2014-08-20T18:30:00.000Z")
.ToLocalTime()
.ToString("yyyy-MM-dd h:mm tt");
My results:
2014-08-20T18:30:00.000Z
2014-08-21 12:00 AM
You may simply try this:
TimeZone.CurrentTimeZone.ToLocalTime(date);
Also check DateTimeOffSet
Represents a point in time, typically expressed as a date and time of
day, relative to Coordinated Universal Time (UTC).
Also
DateTime changedDate = DateTime.SpecifyKind(DateTime.Parse(dateStr),
DateTimeKind.Utc);
DateTime dt = convertedDate.ToLocalTime();

What are valid UTCDateTime type string formats for AIF transfomrmations?

Im am trying to write a .net class that transforms a piece of xml to a AX UtcDateTime type.
The class is used in an inbound transformation.
Original xml:
<DateTime>
<Date>2014-06-12</Date>
<Time>10:52:00</Time>
<Zone>+02:00</Zone>
</DateTime>
My resulting xml leads to an exeption in the exeptionlog:
"The value '2014-06-12T12:52:00+02:00' is not a valid UtcDateTime type."
I think AIF expect the Z at the end of the value, and I am not sure if the localDateTime is mandatory and or if the milliseconds are a requirement.
I would like to know how the UtcDateTime field in transformed xml should be formatted to be accepted by AIF.
Like so:
<MessageHeaderDateTime localDateTime="2014-06-12T10:52:00+02:00">2014-06-12T08:52:00Z</MessageHeaderDateTime>
or like so:
<MessageHeaderDateTime localDateTime="2014-06-12T10:52:00.1108723+02:00">2014-06-12T08:52:00.1108723Z</MessageHeaderDateTime>
or are other things missing?
My Code
DateTime netdttm = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc);
TimeSpan timespan = new TimeSpan(zhour, zminute, 0);
DateTime netdttmoffset = netdttm.Subtract(timespan);
datetime.Value = netdttmoffset;
datetime.localDateTime = netdttmoffset.ToLocalTime();
datetime.localDateTimeSpecified = true;
I use a similar appraoch for the case where I use utcnow.
Problem i that I have limited testing possibilities due to hot-swapping being disbled in the environment where I have to develop my code. So I would like to be certainin about the formatting.
Thanx for your help.
I finally got it to work. My solution:
//declare the AX utcdatetime type from the cs class generate with:
//xsd C:\...\SharedTypes.xsd C:\..\AIFschema.xsd /Classes /Out:C:\location\of\csfile\
AxType_DateTime datetime = new AxType_DateTime();
//Ax store the time in GMT with an optional local time. My XML can have any timezone.
datetime.timezone = AxdEnum_Timezone.GMT_COORDINATEDUNIVERSALTIME;
//I set this to false as i am not interested in actually storing the local time. Plus AX fails over the formatting .net returns.
datetime.timezoneSpecified = false;
//{... left out code to retrieve the hours, minutes etc from my XML}
//declare the .net datetime variable with the values from the xml:
DateTime netdttm = new DateTime(year, month, day, hour, minute, second, millisecond, DateTimeKind.Utc);
DateTime netdttmoffset = new DateTime();
// (optional field) <zone>+01:00</zone>
if (message.Header.DateTime.Zone != null)
{
{... left out code to retrive zone offset info from xml}
TimeSpan timespan = new TimeSpan(zhour, zminute, 0);
netdttmoffset = netdttm.Subtract(timespan);
}
else //no zone, so datetime == GMT datetime.
{
netdttmoffset = netdttm;
}
datetime.Value = netdttmoffset;
datetime.localDateTime = netdttmoffset.ToLocalTime();
//do not output to xml, or AX will fail over this.
datetime.localDateTimeSpecified = false;
Result xml snippet as accepted by AX:
<MessageHeaderDateTime>2014-07-30T16:41:10.001Z</MessageHeaderDateTime>
I found this to be easier. If you want a particular datetime, say Jan 31, 2015 8:00 am, to be stored in AX, the .net code to make it happen would be
DateTime utcDateTime = new DateTime(2015, 1, 31, 8, 0, 0).ToUniversalTime();
var workerStartDate = new AxdExtType_HcmEmploymentStartDateTime
{
Value = utcDateTime
};
The XML generated would be would be <WorkerStartDate>2015-05-12T13:00:00Z</WorkerStartDate>, assuming you are 5 hours behind GMT on the computer that runs the .net code. The AX database will store the value 2015-05-12T13:00:00Z as well.
<dyn:StartDate>2014-06-22T00:00:00.000+02:00</dyn:StartDate>
This format always does the trick for me. (Notice the ms)

Computing milliseconds since 1970 in C# yields different date than JavaScript

I need to compute the JavaScript getTime method in C#.
For simplicity, I chose a fixed date in UTC and compared the C#:
C#
DateTime e = new DateTime(2011, 12, 31, 0, 0, 0, DateTimeKind.Utc);
DateTime s = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
TimeSpan t = (e - s);
var x = t.TotalMilliseconds.ToString();
=> 1325289600000
and the JavaScript results:
JavaScript
var d = new Date(2011, 12, 31, 0, 0, 0)
var utcDate = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds());
utcDate.getTime()
=> 1327960800000
Any hints on what I'm doing wrong?
Thanks!
Javascript months are zero-based.
12 means January of next year.
You want 11.
If you meant for the input to be at UTC, you should be doing this instead:
var ts = Date.UTC(2011,11,31,0,0,0);
As SLaks pointed out, months run 0-11, but even then - you must initialize the date as UTC if you want the response in UTC. In your code, you were initializing a local date, and then converting it to UTC. The result would be different depending on the time zone of the computer where the code is running. With Date.UTC, you get back a timestamp - not a Date object, and it will be the same result regardless of where it runs.
From Chrome's debugging console:
This is the same value returned from your .NET code, which looks just fine, except I would return a long, not a string.
The date JS is wrong I believe. Omit the var utcDate line and output just d.getTime()
The time between two dates is the same, regardless of timezone and offset. Timezones are relative to an ACTUAL point in time, so whether you call .getTime() on the UTC or EST or PST date, it will be the same relative to 1970-1-1 of the same timezone.
2011-12-31 EST - 1970-1-1 EST
== 2011-12-31 PST - 1970-1-1 PST
== 2011-12-31 UTC - 1970-1-1 UTC
EDIT: Per #Slaks above, you also are not using the 0-based month (which I also had no idea about).

Categories

Resources