I'm in the process of porting a C++ program to C#. The program needs to be able to read a file's "modified" timestamp and store it in a List. This is what I have so far:
C# code:
ret = new List<Byte>(); //list to store the timestamp
var file = new FileInfo(filename);
//Get revision date/time
DateTime revTime_lastWriteTime_LT = file.LastWriteTime;
//Copy date/time into the List (binary buffer)
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Month));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Day));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Year % 100)); // 2-digit year
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Hour));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Minute));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Second));
The problem occurs when I read in the Hours value. If the file was modified during daylight savings time (like a summer month), the hour value in the C++ program gets subtracted by one. I can't seem to replicate this in my program. In the MSDN article for DateTime it says under "DateTime values": "local time is optionally affected by daylight saving time, which adds or subtracts an hour from the length of a day". In my C# code I made sure to change my DateTime object to local time using, ToLocalTime(), but apparently I haven't instituted the option that the article is talking about. How do I make sure that my DateTime object in local time subtracts a value when reading in a file that was modified during daylight savings time?
C++ code just in case:
static WIN32_FILE_ATTRIBUTE_DATA get_file_data(const std::string & filename)
{
WIN32_FILE_ATTRIBUTE_DATA ret;
if (!GetFileAttributesEx(filename.c_str(), GetFileExInfoStandard, &ret))
RaiseLastWin32Error();
return ret;
}
//---------------------------------------------------------------------------
static SYSTEMTIME get_file_time(const std::string & filename)
{
const WIN32_FILE_ATTRIBUTE_DATA data(get_file_data(filename));
FILETIME local;
if (!FileTimeToLocalFileTime(&data.ftLastWriteTime, &local))
RaiseLastWin32Error();
SYSTEMTIME ret;
if (!FileTimeToSystemTime(&local, &ret))
RaiseLastWin32Error();
return ret;
}
void parse_asm()
{
// Get revision date/time and size
const SYSTEMTIME rev = get_file_time(filename);
// Copy date/time into the binary buffer
ret.push_back(rev.wMonth);
ret.push_back(rev.wDay);
ret.push_back(rev.wYear % 100); // 2-digit year
ret.push_back(rev.wHour);
ret.push_back(rev.wMinute);
ret.push_back(rev.wSecond);
}
Update for clarity:
In Windows time settings I am in (UTC-05:00) Eastern Time (US & Canada). The file was last modified on Tues Sept 03, 2013 at 12:13:52 PM. The C++ app shows the hour value as 11 and the C# app shows the hour value as 12 using the code above. I need the C# app to show the same hour value as the C++ app.
The bug is actually not with .NET, but with your C++ code. You're using FileTimeToLocalFileTime, which has a well known bug, as described in KB932955:
Note The FileTimeToLocalFileTime() function and the
LocalFileTimeToFileTime() function perform the conversion between UTC
time and local time by using only the current time zone information
and the DST information. This conversion occurs regardless of the
timestamp that is being converted.
So in the example you gave, Sept 03, 2013 at 12:13:52 PM in the US Eastern Time zone should indeed be in daylight saving time. But because it is right now (February 2015) not daylight saving time, you currently get 11 for the hour in your C++ program. If you run the exact same C++ code after next month's transition (March 8th 2015), you will then get 12 for the hour.
The fix for the C++ code is described in the remarks section of the MSDN entry for the FileTimeToLocalFileTime function:
To account for daylight saving time when converting a file time to a local time, use the following sequence of functions in place of using FileTimeToLocalFileTime:
FileTimeToSystemTime
SystemTimeToTzSpecificLocalTime
SystemTimeToFileTime
Now that you understand the bug - if you actually wanted to keep that behavior in C# (which I do not recommend), then you would do the following:
TimeSpan currentOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);
DateTime revTime_LastWriteTime_Lt = file.LastWriteTimeUtc.Add(currentOffset);
The better thing to do would just to leave your current code as is (using file.LastWriteTime), and call the bug fixed.
Sorry, you need to use Add not AddHours, Add accepts TimeSpan. So you're looking for:
file.LastWriteTimeUtc.Add(TimeZoneInfo.Local.BaseUtcOffset);
Related
Hello i am experiencing a strange problem, my scenario is that i am reading the history of google chrome browser stored in sqlite database using c# language. every thing goes fine except the timestamp that chrome stores in epoch format i have to upload the data to server using php and store it in the MYSQL database.
Now my problem is that i can't manage to convert that epoch timestamp to MYSQL based datetime.
for C# i tried following code
public static DateTime FromUnixTime(long unixTime)
{
return epoch.AddSeconds(unixTime);
}
taken from here i tried all available solutions on that link but they did not worked in my case.
for PHP i tried the following code taken from here
echo date("Y-m-d H:i:s", substr($epoch, 0, 10));
but it converts correct if the timestamp is same as mentioned in example but it returns wrong year when executed with my epoch timestamp.
i even tried to solve this problem at MYSQL query level so i searched and tried the following solution taken from here
select from_unixtime(floor(1389422614485/1000));
it does work when i don't replace the example epoch timestamp but when i put my own it did not work
kindly help me to get rid of this strange irritating problem does not matter at which layer you provide solution all are acceptable following languages are preferred
C#
PHP
MYSQL Query
example epoch timestamp is foloowing
13209562668824233
i do know that with respect to length its not same as in examples but note that chrome does convert this efficiently.
As explained by this answer, the Chrome timestamp is not equal to Unix epoch time. This is why you're not getting the results you expect from such methods. It's actually microseconds since the 1st Jan, 1601 (as opposed to Unix epoch time's seconds since 1st Jan, 1970).
You can test your WebKit timestamp here, where you'll see it returns Tuesday, 6 August 2019 10:57:48 (UTC).
So to convert this in code, we should first subtract the difference between 1970 and 1601 (in microseconds) and then divde the value by 1 million to get seconds (C# solution):
public static DateTime ConvertWebKitTime(long webkitEpoch)
{
const long epochDifferenceMicroseconds = 11644473600000000; // difference in microseconds between 1601 and 1970
var epoch = (webkitEpoch - epochDifferenceMicroseconds) / 1000000; // adjust to seconds since 1st Jan 1970
return DateTimeOffset.FromUnixTimeSeconds(epoch).UtcDateTime; // convert to datetime
}
A solution for PHP (64 Bit, without Milliseconds) is
$ts = 13209562668824233;
$date = date_create("1601-1-1 UTC")
->modify((int)($ts/1000000)." Seconds")
->format('Y-m-d H:i:s')
; //"2019-08-06 10:57:48"
For more details see: What is the format of Chrome's timestamps?
We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();
I'm using DirectoryInfo.CreationTime to get the date when the directory is created
however it returns strange date {21/11/1617 0:00:00}
var directoryInfo = new DirectoryInfo("C:\\testFolder");
var lastWriteTime = directoryInfo.LastWriteTime; // correct value
var creationTime = directoryInfo.CreationTime; // Date = {21/11/1617 0:00:00}
var creationTimeUtc = directoryInfo.CreationTimeUtc; // Date = {21/11/1617 0:00:00}
any idea?
In Addition:
The folder located in NAS share, some folders returns the correct value and some not
I did the following tests:
Restart my machine and check that the data and time is set correctly
Run the application from another machine
recreate the application using .NET 4.0 VS2010
Run the application from different OS windows 7
All returns the same value. however if i select folder properties the creation date is set to 2008.
Is this a bug?
I can shed some light on the "strange date".
Windows file times are based off of 1/1/1601.
A file time is a 64-bit value that represents the number of
100-nanosecond intervals that have elapsed since 12:00 A.M. January 1,
1601 Coordinated Universal Time (UTC). The system records file times
when applications create, access, and write to files.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724290(v=vs.85).aspx
It would appear that your file system is reporting a 16 year offset to DirectoryInfo (which inherits from the FileSystemInfo class, which is calling GetFileAttributesEx()).
The .Net wrapper
public DateTime CreationTimeUtc
{
get{
long fileTime = (long)((ulong)this._data.ftCreationTimeHigh << 32 | (ulong)this._data.ftCreationTimeLow);
return DateTime.FromFileTimeUtc(fileTime);
}
}
DateTime.FromFileTimeUtc adds a value equal to 1/1/1601:
long ticks = fileTime + 504911232000000000L;
return new DateTime(ticks, DateTimeKind.Utc);
I can't find any significance to the offset (16 years). It seems too large to be DST errors or leap years, even accumulated over centuries.
I do think it is peculiar that both CreationTime and CreationTimeUtc return exactly the same date (unless your local time is the same as UTC).
The msdn documentation on CreationTime talks about a bunch of issues which could cause this
Check out the Remarks section of this link below
http://msdn.microsoft.com/en-IN/library/system.io.filesysteminfo.creationtime.aspx
It could be a cached value which is not updated. For this you could use the Refresh method. As indicated in the comments, some old platforms also can probably give you trouble.
I am getting the "LastWriteTime" of my executable and comparing it to an internal DateTime that I have set. If the LastWriteTime is less than or equal to the internal DateTime then I will clear two tables from a database.
This code works great for me in the Pacific Time Zone. But if a user is in another time zone, (example 4 hours ahead of me), then it does not work because the "LastWriteTime" returns the time converted to their time zone. For example, I am looking for the value of "12/12/2012 8:38:12 AM" and if they are 4 hours ahead of me, this value gets automatically changed to "12/12/2012 12:38:12 PM" on their systems.
Can someone please show me what I should modify in my code to take into account for different time zones so the "LastWriteTime" and my 'build2023_EXE_Date' variable both return the same Date/Time so my comparision of the two date/time values don't fail regardless of what time zone my end user is in?
I am using .NET 3.5, not .Net 4.x
//http://stackoverflow.com/questions/1600962/displaying-the-build-date
string w_file = "MyEXE.exe";
string w_directory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
Path.DirectorySeparatorChar + "MyEXE";
DateTime currentExeTime = File.GetLastWriteTime(System.IO.Path.Combine(w_directory, w_file));
DateTime build2023_EXE_Date = new DateTime(2012, 12, 12, 8, 38, 12); //"12/12/2012 8:38:12 AM"
//We need to truncate the millisecond time off of the EXE LastWriteTime
//or else when we compare to our internal DateTime build2323_EXE_Date value,
//it will not match
//http://stackoverflow.com/questions/1004698/how-to-truncate-milliseconds-off-of-a-net-datetime
currentExeTime = new DateTime(
currentExeTime.Ticks - (currentExeTime.Ticks % TimeSpan.TicksPerSecond),
currentExeTime.Kind
);
if (currentExeTime <= build2023_EXE_Date) //If previous build matches or is before the Build 2023 date then clear these two tables.
{
//This will fail the comparision if the user is in a different time zone than me.
//Clear tables
}
Unless you've got a specific need to keep dates in local time or have an associated time zone, I suggest you use universal time instead. This makes working with dates far easier because they all compare sanely, and it can actually be more performant (when you request DateTime.Now, .NET calls DateTime.UtcNow and then performs a relatively expensive adjustment to local time).
Another option is to use DateTimeOffset, which stores a date with an offset (not a time zone! -- for instance, DST will give you different offsets) and makes comparisons as easy as a universal DateTime. Unfortunately, though, GetLastWriteTime doesn't use DateTimeOffset so this might not work for you.
Use the DateTime ToUniversalTime() method
I have a legacy C++-based application that timestamps incoming network traffic using the CRT _ftime() function. The _ftime() function returns a _timeb structure, which has a 32-bit and a 64-bit implementation. We are using the 32-bit implementation, which looks like this:
struct _timeb {
long time; // 4 bytes
unsigned short millitm; // 2 bytes
short timezone; // 2 bytes
short dstflag; // 2 bytes
};
From the MSDN documentation, here is how each field is interpreted:
dstflag - nonzero if daylight savings time is currently in effect for the local time zone (see _tzset for an explanation of how daylight savings time is determined.)
millitm - fraction of a second in milliseconds
time - time in seconds since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC).
timezone - difference in minutes, moving westward, between UTC and local time. The value of timezone is set from the value of the global variable _timezone (see _tzset).
I am re-working the portion of the code that does the timestamping to use C# in .NET 3.5. Timestamps are now generated using the System.DateTime structure, but I still need to convert them back to the _timeb structure so the legacy C++ code can operate on them. Here is how I am doing that in my managed C++ bridge library:
DateTime dateTime = DateTime::UtcNow;
DateTime baseTime(1970, 1, 1, 0, 0, 0, DateTimeKind::Utc);
TimeSpan delta = dateTime - baseTime;
_timeb timestamp;
timestamp.time = delta.TotalSeconds;
timestamp.millitm = dateTime.Millisecond;
timestamp.dstflag = TimeZoneInfo::Local->IsDaylightSavingTime(dateTime) ? 1 : 0;
timestamp.timezone = TimeZoneInfo::Local->BaseUtcOffset.TotalMinutes * -1;
From what I can tell, this appears to reconstruct the _timeb structure as if I had called _ftime() directly, and that's good. The thing is, timestamps are a critical piece of our application, so this has to be right.
My question is two-fold.
Is my algorithm flawed somehow? Does anyone see anything obvious that I've missed? Are there boundary conditions where this won't work right?
Is there a better way to do the conversion? Does .NET have a way to do this in a more straightforward manner?
You're aware of the Y2K38 problem? I assume you checked the sign of .timezone. Avoid the cleverness of using dateTime.Millisecond, that just confuses the next guy. Looks good otherwise.