we are developing a C# web application that has to deal with Unix timestamps and C# DateTime objects. A timestamp has to be converted into a DateTime object.
The following example shows my problem: The DateTime should be '18.10.2011 14:02:32'
System.DateTime time = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
time = time.AddSeconds(1318939352);
System.Console.Out.WriteLine("Time: " + time); // -> 18.10.2011 12:02:32
If I call ToLocalTime() on my developer machine, the DateTime is correct:
System.DateTime time = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
time = time.AddSeconds(1318939352).ToLocalTime();
System.Console.Out.WriteLine("Time: " + time); // -> 18.10.2011 14:02:32
But the application will run on servers which are hosted in another timezone (GMT Standard Time), so I have to deal with a different time zone and the second example fails on this servers.
Independent of where I host the application, the date in this case should always be printed as 18.10.2011 14:02:32.
Does anyone know how I can do this? Thanks in advance!
Best Regards,
Thorsten
You can have a look TimeZoneInfo
public struct DateTimeWithZone
{
private readonly DateTime utcDateTime;
private readonly TimeZoneInfo timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
{
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, timeZone);
this.timeZone = timeZone;
}
public DateTime UniversalTime
{
get { return utcDateTime; }
}
public TimeZoneInfo TimeZone
{
get { return timeZone; }
}
public DateTime LocalTime
{
get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); }
}
}
Related
A while ago I posted the following, which was gladly answered by olitee (all credit goes to him for the solution):
Convert DateTime value to Final Fantasy XIV Eorzea Game Time
I was trying to add features to my code and one would require to be able to put that Eorzea time (FFXIV) back to Earth time for alerts.
The following code, provided by olitee, was converting Earth time to Eorzea time just fine:
public static class EorzeaDateTimeExtention
{
public static DateTime ToEorzeaTime(this DateTime date)
{
const double EORZEA_MULTIPLIER = 3600D/175D;
long epochTicks = date.ToUniversalTime().Ticks - (new DateTime(1970, 1, 1).Ticks);
long eorzeaTicks = (long)Math.Round(epochTicks * EORZEA_MULTIPLIER);
return new DateTime(eorzeaTicks);
}
}
How would I achieve the opposite? I tried to revert the mathematical calculations but apparently it keeps giving me negative epochTicks which results in error whenever I try the conversion.
Apparently I am missing something or I got it wrong at some point.
My understanding of the ticks is quite limited.
Any help and/or tips would be greatly appreciated.
Thanks a lot in advance.
The ToEarthTime method should give you the earth time.
class Program
{
static void Main(string[] args)
{
var now = DateTime.Now;
var ff = now.ToEorzeaTime();
Console.WriteLine($"Now: {now} | FF: {ff}");
var ffNew = new DateTime(ff.Ticks, DateTimeKind.Utc);
var nowNew = ffNew.ToEarthTime();
Console.WriteLine($"Now: {nowNew} | FF: {ffNew}");
Console.ReadLine();
}
}
public static class Converter
{
private const double EORZEA_MULTIPLIER = 3600D / 175D;
public static DateTime ToEorzeaTime(this DateTime date)
{
long epochTicks = date.ToUniversalTime().Ticks - (new DateTime(1970, 1, 1).Ticks);
long eorzeaTicks = (long)Math.Round(epochTicks * EORZEA_MULTIPLIER);
return new DateTime(eorzeaTicks);
}
public static DateTime ToEarthTime(this DateTime date)
{
var epochTicks = (long) Math.Round(date.Ticks/EORZEA_MULTIPLIER);
var earthTicks = epochTicks + new DateTime(1970, 1, 1).Ticks;
var utc = new DateTime(earthTicks, DateTimeKind.Utc);
return utc.ToLocalTime();
}
}
I have to select changelists from perforce the problem is when I extracted information but the problem is that the date and the time look not significative so how can I change this string to significative date and time
example of result 1361898522
the code:
P4Command cm1 = new P4Command(ps, "changes", true, String.Format("{0}", deppath1));
Options opchanges = new Options();
opchanges.Add(op1,op2);
P4CommandResult results1 = cm1.Run(opchanges);
TaggedObjectList listfiledown1 = new TaggedObjectList();
listfiledown1 = (results1.TaggedOutput);
foreach (TaggedObject obj in listfiledown1)
{
foreach (String s in obj.Keys)
{
String value = "n/a";
obj.TryGetValue(s, out value);
var changeList = value.Split ('#');
}
}
If the value 1361898522 is meant to be Tue, 26 Feb 2013 17:08:42 UTC, then it looks like this is a Unix timestamp - a number of seconds since the Unix epoch. This is easy to do in C#:
private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0,
DateTimeKind.Utc);
...
public static DateTime FromUnixTimestamp(long seconds)
{
return UnixEpoch + TimeSpan.FromSeconds(seconds);
}
Note the UTC DateTimeKind so that the epoch is appropriately UTC rather than in the system local time zone.
Using my Noda Time project it's even easier, as of version 1.1:
Instant timestamp = Instant.FromSecondsSinceUnixEpoch(seconds);
I suspect that the date time values are expressed in Unix time: the number of seconds since January 1, 1970.
For example, if you write:
var epoc = new DateTime(1970, 01, 01);
dt = epoc + TimeSpan.FromSeconds(1361898522);
Console.WriteLine(dt);
The result is:
2013/02/26 17:08:42
private static DateTime FromMS(long microSec)
{
long milliSec = (long)(microSec / 1000);
DateTime startTime = new DateTime(1970, 1, 1);
TimeSpan time = TimeSpan.FromMilliseconds(milliSec);
DateTime v = new DateTime(time.Ticks);
DateTime result = new DateTime(startTime.Year + v.Year, startTime.Month + v.Month, startTime.Day + v.Day, startTime.Hour + v.Hour, startTime.Minute + v.Minute, startTime.Millisecond + v.Millisecond);
return result;
}
This result is wrong...
Why ???
You already have the result of the conversion to milliseconds when you do:
TimeSpan time = TimeSpan.FromMilliseconds(milliSec);
DateTime v = new DateTime(time.Ticks); //This is the result
If you want to add the milliseconds to UNIX time, then all you have to do is:
TimeSpan time = TimeSpan.FromMilliseconds(milliSec);
DateTime result = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
result = result.Add(time);
If the time isn't in UTC then omit the DateTimeKind.Utc part, but it's generally a good idea to keep the time in UTC and only convert to local time when needed.
private static DateTime FromMS(long microSec)
{
long milliSec = (long)(microSec / 1000);
DateTime startTime = new DateTime(1970, 1, 1);
TimeSpan time = TimeSpan.FromMilliseconds(milliSec);
return startTime.Add(time);
}
I use this method to convert from a Unix Epoch (with milliseconds) to a DateTime object
private static readonly DateTime UnixEpochStart =
DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc);
public static DateTime ToDateTimeFromEpoch(this long epochTime)
{
DateTime result = UnixEpochStart.AddMilliseconds(epochTime);
return result;
}
long ticks = new DateTime(1970, 1, 1).Ticks;
DateTime dt = new DateTime(ticks);
dt.AddMilliseconds(milliSec);
Try this.
TimeSpan time = TimeSpan.FromMilliseconds(1509359657633);
DateTime date = new DateTime(1970, 1, 1).AddTicks(time.Ticks);
This will convert milliseconds into a correct DateTime.
NOTE:- If you get the milliseconds from JS like Date.now() the millisecond you received here is for UTC. So when you convert to C# DateTime, you will get DateTime in UTC time
Assuming you have a Unix timestamp, what would be an easy and/or elegant way to check if that timestamp was some time yesterday?
I am mostly looking for solutions in Javascript, PHP or C#, but pseudo code and language agnostic solutions (if any) are welcome as well.
In C# you could use this:
bool isYesterday = DateTime.Today - time.Date == TimeSpan.FromDays(1);
You can use this in C#:
bool isYesterday = (dateToCheck.Date.AddDays(1) == DateTime.Now.Date);
PHP:
$isYesterday = date('Ymd', $timestamp) == date('Ymd', strtotime('yesterday'));
In pseudo code, to compare timestamps:
get current Unix timestamp
transform the retrieved timestamp to a date
subtract 1 day from the date
transform the timestamp to test to a date
compare both dates. If they're equal the tested timestamp was yesterday.
Watch out for timezones if you show the results to a user. For me it's now 13:39 on July 9 2010. A timestamp for 14 hours ago for me is yesterday. But for someone in a different timezone where it's now 15:39, 14 hours ago wasn't yesterday!
Another problem might be systems with a wrong time/date setup. For example if you use JavaScript and the system time of the visitors PC is wrong, the program may come to a wrong conclusion. If it's essential to get a correct answer, retrieve the current time from a known source with a correct time.
An example in Smalltalk using Pharo/Squeak
(Date year: 2014 month: 4 day: 24) = Date yesterday
This accepts an optional DateTimeZone object. If it's not given, it uses the currently set default timezone.
<?php
function isYesterday($timestamp, $timezone = null) {
$t = new DateTime(null, $timezone);
$t->setTimestamp($timestamp);
$t->setTime(0,0);
$yesterday = new DateTime("now", $timezone);
$yesterday->setTime(0,0);
$yesterday = $yesterday->sub(new DateInterval('P1D'));
return $t == $yesterday;
}
Another C# example:
bool isYesterday = DateTime.Now.Date.AddDays(-1) == dateToCheck.Date;
Code:
static class ExtensionMethods
{
private static readonly DateTime UnixStart = new DateTime(1970, 1, 1, 0, 0, 0, 0);;
public static bool IsYesterday(this int unixTime)
{
DateTime convertedTime = UnixStart.AddSeconds(unixTime);
return convertedTime.Date == DateTime.Now.AddDays(-1).Date;
}
public static bool IsYesterday(this DateTime date)
{
return date.Date == DateTime.Now.AddDays(-1).Date;
}
}
Examples:
public class Examples
{
public void Tests()
{
if (1278677571.IsYesterday()) System.Console.WriteLine("Is yesterday");
DateTime aDate = new DateTime(2010, 12, 31);
if (aDate.IsYesterday()) System.Console.WriteLine("Is yesterday");
}
}
In JavaScript, you could write
var someDate = new Date(2010, 6, 9);
Date.yesterday.date == someDate.date // true
Left out needless implementation details, but it's possible. Ok, there ya go :)
(function() {
function date(d) {
var year = d.getFullYear();
var month = d.getMonth();
var day = d.getDate();
return new Date(year, month, day);
}
Object.defineProperty(Date, 'yesterday', {
enumerable: true,
configurable: false,
get: function() {
var today = new Date();
var millisecondsInADay = 86400000;
var yesterday = new Date(today - millisecondsInADay);
return yesterday;
},
set: undefined
});
Object.defineProperty(Date.prototype, 'date', {
enumerable: true,
configurable: true,
get: function() {
return date(this).valueOf();
},
set: undefined
});
})();
C#
TimeSpan difference = DateTime.Now.Date - olderDate.Date;
bool isYesterday = difference.TotalDays == 1;
You can give this function a shot:
public bool IsFromYesterday(long unixTime) {
DateTime convertedTime = new DateTime(1970, 1, 1, 0, 0, 0, 0);
convertedTime.AddSeconds(unixTime);
DateTime rightNow = DateTime.Now;
DateTime startOfToday = DateTime.Today;
DateTime startOfYesterday = startOfToday - new TimeSpan(1, 0, 0, 0);
if (convertedTime > startOfYesterday && convertedTime < rightNow)
return true;
else
return false;
}
In my C# app, I pass a string variable that is of format yyyymmdd-yyyymmdd that represents a from and to date. I want to get the start and end times for these dates respectively. Currently I have the below code but was wondering if there was more of an elegant solution?
So for pdr = 20090521-20090523 would get "20090521 00:00:00" and "20090523 23:59:59"
private void ValidateDatePeriod(string pdr, out DateTime startDate,
out DateTime endDate)
{
string[] dates = pdr.Split('-');
if (dates.Length != 2)
{
throw new Exception("Date period is of incorrect format");
}
if (dates[0].Length != 8 || dates[1].Length != 8)
{
throw new Exception("Split date periods are of incorrect format");
}
startDate = DateTime.ParseExact(dates[0] + " 00:00:00",
"yyyyMMdd HH:mm:ss", null);
endDate = DateTime.ParseExact(dates[1] + "23:59:59",
"yyyyMMdd HH::mm:ss", null);
}
I am surprised to see how an incorrect answer received so many upvotes:
The correct version would be as follows:
public static DateTime StartOfDay(this DateTime theDate)
{
return theDate.Date;
}
public static DateTime EndOfDay(this DateTime theDate)
{
return theDate.Date.AddDays(1).AddTicks(-1);
}
You could define two extension methods somewhere, in a utility class like so :
public static DateTime EndOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 999);
}
public static DateTime StartOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
}
And then use them in code like so :
public DoSomething()
{
DateTime endOfThisDay = DateTime.Now.EndOfDay();
}
If you are only worried about .Net precision...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddTicks(-1).AddDays(1);
You really don't need to concatenate extra values onto the string for the time portion.
As an addendum, if you are using this for a query against, for example, a database...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddDays(1);
With a query of...
WHERE "startDate" >= #startDate AND "endDate" < #endDate
Then the precision issues noted in the comments won't really matter. The endDate in this case would not be part of the range, but the outside boundary.
The DateTime object has a property called Date which will return just the date portion. (The time portion is defaulted to 12:00 am).
I would recommend as a more elegant solution (IMHO) that if you want to allow any datetime on the last day, then you add 1 day to the date, and compare to allow times greater than or equal to the start date, but strictly less than the end date (plus 1 day).
// Calling code. beginDateTime and endDateTime are already set.
// beginDateTime and endDateTime are inclusive.
// targetDateTime is the date you want to check.
beginDateTime = beginDateTime.Date;
endDateTime = endDateTime.Date.AddDays(1);
if ( beginDateTime <= targetDateTime &&
targetDateTime < endDateTime )
// Do something.
public static class DateTimeExtension {
public static DateTime StartOfTheDay(this DateTime d) => new DateTime(d.Year, d.Month, d.Day, 0, 0,0);
public static DateTime EndOfTheDay(this DateTime d) => new DateTime(d.Year, d.Month, d.Day, 23, 59,59);
}
I use the following in C#
public static DateTime GetStartOfDay(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfDay(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
}
Then in MS SQL I do the following:
if datepart(ms, #dateEnd) = 0
set #dateEnd = dateadd(ms, -3, #dateEnd)
This will result in MS SQL time of 23:59:59.997 which is the max time before becoming the next day.
You could simply use:
new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
Which will work in MS SQL, but this is not as accurate in .Net side.
That's pretty much what I would do, with some small tweaks (really no big deal, just nitpicking):
The TryParse()/TryParseExact() methods should be used which return false instead of throwing exceptions.
FormatException is more specific than Exception
No need to check for Length == 8, because ParseExact()/TryParseExact() will do this
"00:00:00" and "23:59:59" are not needed
return true/false is you were able to parse, instead of throwing an exception (remember to check value returned from this method!)
Code:
private bool ValidateDatePeriod(string pdr, out DateTime startDate,
out DateTime endDate)
{
string[] dates = pdr.Split('-');
if (dates.Length != 2)
{
return false;
}
// no need to check for Length == 8 because the following will do it anyway
// no need for "00:00:00" or "23:59:59" either, I prefer AddDays(1)
if(!DateTime.TryParseExact(dates[0], "yyyyMMdd", null, DateTimeStyles.None, out startDate))
return false;
if(!DateTime.TryParseExact(dates[1], "yyyyMMdd", null, DateTimeStyles.None, out endDate))
return false;
endDate = endDate.AddDays(1);
return true;
}
I think we're doing it wrong. There is no such thing as the end of the day. AddTick(-1) only works under the convention that there are no time intervals smaller than a tick. Which is implementation dependent. Admittedly the question comes with a reference implementation, namely the .Net Framework DateTime class, but still we should take this as a clue that the function we really want is not EndOfDay() but StartOfNextDay()
public static DateTime StartOfNextDay(this DateTime date)
{
return date.Date.AddDays(1);
}
The issue above regarding the few milliseconds can be resolved by querying the database with the next day's start date.
For example:
SELECT * FROM temp WHERE createdDate >= fromDate AND createdDate < toDate
Using the extension methods below you could set the from and to dates to:
DateTimeOffset fromDate = DateTimeOffset.UtcNow.StartOfDay();
DateTimeOffset toDate = DateTimeOffset.UtcNow.EndOfDay();
public static class DateExtentions
{
public static DateTimeOffset StartOfDay(this DateTimeOffset dateTime)
{
return new DateTimeOffset(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0, 0, dateTime.Offset);
}
public static DateTimeOffset EndOfDay(this DateTimeOffset dateTime)
{
return dateTime.StartOfDay().AddDays(1);
}
public static DateTimeOffset StartOfMonth(this DateTimeOffset dateTime)
{
return new DateTimeOffset(dateTime.Year, dateTime.Month, 1, 0, 0, 0, 0, dateTime.Offset);
}
public static DateTimeOffset EndOfMonth(this DateTimeOffset dateTime)
{
return dateTime.StartOfMonth().AddMonths(1);
}
public static DateTimeOffset StartOfYear(this DateTimeOffset dateTime)
{
return new DateTimeOffset(dateTime.Year, 1, 1, 0, 0, 0, 0, dateTime.Offset);
}
public static DateTimeOffset EndOfYear(this DateTimeOffset dateTime)
{
return dateTime.StartOfYear().AddYears(1);
}
}
For SQL Server (version 2008 R2 tested) this ranges works.
StarDate '2016-01-11 00:00:01.990'
EndDate '2016-01-19 23:59:59.990'
Seems like ticks is greater that the last second of day and automatically round to next day. So i test and works, i made a dummy table with two dates for check what values is sql server catching and inserting in the stored procedure those parameters.
In Java 8, you can do it using LocalDate as follows:
LocalDate localDateStart = LocalDate.now();
Date startDate = Date.from(localDateStart.atStartOfDay(ZoneId.systemDefault()).toInstant());
LocalDate localDateEnd = localDateStart.plusDays(1);
Date endDate = Date.from(localDateEnd.atStartOfDay(ZoneId.systemDefault()).toInstant());