I have this line of code:
double seconds = new DateTime(2006,7,6,12,1,0,DateTimeKind.Local).Subtract(new DateTime(1970,1,1,0,0,0,DateTimeKind.Local).TotalSeconds;
This was not the right number I wanted, so I tried the following:
double seconds = new DateTime(2006,7,6,12,1,0,DateTimeKind.Local).Subtract(new DateTime(1970,1,1,0,0,0,DateTimeKind.Utc).TotalSeconds;
(The difference is that in one case, I use local time for the epoch, and in the other, I use UTC). Interestingly though, they're both giving me the same value, and I don't know why this is. I live at -600 GMT, so DateTimeKind.Local should actually affect things.
Thanks in advance!
In the DateTimeKind page on MSDN (http://msdn.microsoft.com/en-us/library/shx7s921.aspx), it states:
The members of the DateTimeKind enumeration are used in conversion operations between local time and Coordinated Universal Time (UTC), but not in comparison or arithmetic operations. For more information about time conversions, see Converting Times Between Time Zones.
The advice there says to use TimeZoneInfo.ConvertTimeToUtc
So, based on that, the code should probably be modified to:
double seconds = new DateTime(2006,7,6,12,1,0,DateTimeKind.Local).Subtract(TimeZoneInfo.ConvertTimeToUtc(new DateTime(1970,1,1,0,0,0,DateTimeKind.Local)).TotalSeconds
Try this:
namespace ConsoleApplication1
{
using System;
class Program
{
static void Main( string[] args )
{
var laterDate = new DateTime( 2006, 7, 6, 12, 1, 0 );
var earlyDate = new DateTime( 1970, 1, 1, 0, 0, 0 );
var diff = laterDate.ToUniversalTime().Subtract( earlyDate.ToUniversalTime() );
var seconds = diff.TotalSeconds;
}
}
}
Related
I have a code where I am calculating some intervals between dates, and to do that I have a defined interval time that I add to one date, to do that I see 2 ways, but I don't understand the difference, for me they are same :
var timespan = new TimeSpan(0, 0, 5);
var d1 = new DateTime(2010, 1, 1, 8, 0, 15);
var newDateWithTimeSpan = d1.Add(timespan);
var newDateWithSeconds = d1.AddSeconds(5);
Console.WriteLine(newDateWithTimeSpan);
Console.WriteLine(newDateWithSeconds);
No, there's no difference between the two ways you're computing the new DateTime value. There are often multiple ways of expressing the same intent, particularly with DateTime. (You could have used d1 + timespan as another option, for example.)
While this isn't the actual implementation, you can imagine that AddSeconds is implemented like this:
public DateTime AddSeconds(double seconds) =>
this.Add(TimeSpan.FromSeconds(seconds));
It's just a convenience method.
I'd argue that using TimeSpan.FromSeconds in your code is a clearer way of expressing "I want to create a TimeSpan that represents 5 seconds" but that's a slightly separate matter.
I have a specific problem I've been trying to solve, and I think I have the right pieces - I'm just putting them together incorrectly. It might be more of a math question than a coding one.
So basically what I want to be able to do is find where "now" is within an arbitrary recurring time period (say, 43 minutes), given a known DateTime that this period recurred. So you have an anchor point, and from that anchor point, you know that every 43 minutes this period starts over, where is "now" in the current period?
I'm sure it involves division and/or modulo, and likely a subtraction using the anchor...so I've been toying with this code, but it isn't giving me the results I'm looking for:
using System;
public class Program
{
public static void Main()
{
TimeSpan interval = new TimeSpan(0, 43, 0);
DateTime anchor = new DateTime(2018, 1, 5, 7, 0, 49);
DateTime now = DateTime.Now;
TimeSpan left = new TimeSpan((now - anchor).Ticks % interval.Ticks);
Console.WriteLine(left);
}
}
Can someone tell me the piece I'm missing here? I'm not entirely sure what mathematical operations DateTime supports, or which ones I should be using in this instance.
Thanks.
Assuming your anchor always in past, you can use this code. It will print amount of completed periods and how much time passed from begin of last period
var anchor = new DateTime(2018, 1, 5, 13, 20, 17);
var interval = new TimeSpan(0, 43, 0);
var now = DateTime.Now;
var seconds = (ulong) (now - anchor).TotalSeconds;
var intervalSeconds = (ulong) interval.TotalSeconds;
var cycles = seconds / intervalSeconds;
var momentInInterval = TimeSpan.FromSeconds(seconds % intervalSeconds);
Console.WriteLine($"{cycles} cycles passed. {momentInInterval} passed from last period");
I'm using TotalSeconds, you can change it to TotalMilliseconds to be more accurate
If you want to know how much time until the next iteration you could do something like this
TimeSpan interval = new TimeSpan(0, 43, 0);
DateTime anchor = new DateTime(2018, 1, 5, 7, 0, 49);
var iterations = DateTime.Now.Subtract(anchor).Ticks / interval.Ticks;
DateTime current = anchor;
for(var i = 0; i < iterations; i++)
current = current.AddTicks(interval.Ticks);
var untilNext = DateTime.Now.Subtract(current);
Console.Write(untilNext);
You can output the amount of past iterations, the current amount of time from the last and how much until next.
Due to difficulties I experienced trying to call the DotNetOAuth CryptoKey constructor I started to investigate the .Net System.DateTime structure. According to what I've read, this object is actually represented by a 64 bit signed integer, with the "Ticks" encoded in the lower 62 bits and the Kind encoded in the upper 2 bits (IOW, it's a concatenation of the 2 bit Kind and 62 bit ticks).
Now I wanted to actually "see" this so I constructed a small C# program that created three System.DateTime objects as so:
DateTime dtUtc = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Utc);
DateTime dtLocal = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Local);
DateTime dtU = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Unspecified);
I then dumped the ticks property for each and, as expected, they were all equal. Finally, I applied .ToBinary()
long bitUtc = dtUtc.ToBinary();
long bitLocal = dtLocal.ToBinary();
long bitU = dtU.ToBinary();
These longs were all different, again as expected. HOWEVER, I then tried to "inspect" the upper two bits to see which state corresponded to what settings, and found that the upper two bits were set the same in all three. I used the following routine to return the bit status:
public static bool IsBitSet<T>(this T t, int pos) where T : struct, IConvertible
{
var value = t.ToInt64(CultureInfo.CurrentCulture);
return (value & (1 << pos)) != 0;
}
(I got this from another post on SO), and called it like this:
Boolean firstUtc = Class1.IsBitSet<long>(bitUtc, 63);
Boolean secondUtc = Class1.IsBitSet<long>(bitUtc, 62);
Boolean firstLocal = Class1.IsBitSet<long>(bitLocal, 63);
Boolean secondLocal = Class1.IsBitSet<long>(bitLocal, 62);
Boolean firstU = Class1.IsBitSet<long>(bitU, 63);
Boolean secondU = Class1.IsBitSet<long>(bitU, 62);
Again, the first and second bits were set the same in all three (first was true, second false). I don't understand this, as I THOUGHT these would all be different, corresponding to the different SystemKind values.
Finally, I did some more reading and found (or at least it was said in one source) that MS doesn't serialize the Kind information in .ToBinary(). OK, but then why are the outputs of the .ToBinary() method all different?
I would appreciate info from anyone who could point me in the direction of a resource that would help me understand where I've gone wrong.
These longs were all different, again as expected. HOWEVER, I then tried to "inspect" the upper two bits to see which state corresponded to what settings, and found that the upper two bits were set the same in all three.
I really don't think that's the case - not with the results of ToBinary. Here's a short but complete program demonstrating the difference, using your source data, showing the results as hex (as if unsigned):
using System;
class Test
{
static void Main()
{
DateTime dtUtc = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Utc);
DateTime dtLocal = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Local);
DateTime dtU = new System.DateTime(2014, 4, 29, 9, 10, 30, System.DateTimeKind.Unspecified);
Console.WriteLine(dtUtc.ToBinary().ToString("X16"));
Console.WriteLine(dtLocal.ToBinary().ToString("X16"));
Console.WriteLine(dtU.ToBinary().ToString("X16"));
}
}
Output:
48D131A200924700
88D131999ECDDF00
08D131A200924700
The top two bits are retrospectively 01, 10 and 00. The other bits change for the local case too, as per Marcin's post - but the top two bits really do indicate the kind.
The IsBitSet method is broken because it's left-shifting an int literal rather than a long literal. That means the shift will be mod 32, rather than mod 64 as intended. Try this instead:
public static bool IsBitSet<T>(this T t, int pos) where T : struct, IConvertible
{
var value = t.ToInt64(CultureInfo.CurrentCulture);
return (value & (1L << pos)) != 0;
}
Finally, I did some more reading and found (or at least it was said in one source) that MS doesn't serialize the Kind information in .ToBinary().
It's easy to demonstrate that's not true:
using System;
class Test
{
static void Main()
{
DateTime start = DateTime.UtcNow;
Show(DateTime.SpecifyKind(start, DateTimeKind.Utc));
Show(DateTime.SpecifyKind(start, DateTimeKind.Local));
Show(DateTime.SpecifyKind(start, DateTimeKind.Unspecified));
}
static void Show(DateTime dt)
{
Console.WriteLine(dt.Kind);
DateTime dt2 = DateTime.FromBinary(dt.ToBinary());
Console.WriteLine(dt2.Kind);
Console.WriteLine("===");
}
}
ToBinary() works differently for different DateTimeKind. You can see it on .NET source code:
public Int64 ToBinary() {
if (Kind == DateTimeKind.Local) {
// Local times need to be adjusted as you move from one time zone to another,
// just as they are when serializing in text. As such the format for local times
// changes to store the ticks of the UTC time, but with flags that look like a
// local date.
// To match serialization in text we need to be able to handle cases where
// the UTC value would be out of range. Unused parts of the ticks range are
// used for this, so that values just past max value are stored just past the
// end of the maximum range, and values just below minimum value are stored
// at the end of the ticks area, just below 2^62.
TimeSpan offset = TimeZoneInfo.GetLocalUtcOffset(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
Int64 ticks = Ticks;
Int64 storedTicks = ticks - offset.Ticks;
if (storedTicks < 0) {
storedTicks = TicksCeiling + storedTicks;
}
return storedTicks | (unchecked((Int64) LocalMask));
}
else {
return (Int64)dateData;
}
}
That's why you get different bits - local time is adjusted before transformed into bits, and so it does no longer match utc time.
I try to compare Datetime.Now with a Datetime variable I set, using the Datetime.CompareTo() method. I use a timer to compare these every second and display the result, but as the current time approaches the time I set, the result changes from 1 to -1, but never 0, which means these two are never equal. I'm suspecting the Datetime structure contains milliseconds?
You're suspecting correctly. It goes further than milliseconds though. The maximum resolution is the "tick", which is equal to 100 nanoseconds.
As other have mentioned here, the resolution is 100ns.
The easiest approach would be to take your DateTime and subtract DateTime.Now. You then end up with a TimeSpan. If the TimeSpan's TotalSeconds property is 0, the difference between them is less than a second.
You are correct in your suspicion. The DateTime struct smallest unit is the "Tick" which is measured in units of 100ns. (One tick is 100ns)
What you more likely want to do is check if everything down to the seconds is equal and you can do that like this by first comparing the Date property and then compare the hour, minute and second properties individually
DateTime comparison is more exact than comparing with seconds. In your scenario, you can define an "error range", e.g. if the gap between two DateTime is less than 1 second, they are considered to be the same(in your program).
Try this... (but change the test date, of course)
DateTime d1 = new DateTime(2011, 12, 27, 4, 37, 17);
DateTime d2 = DateTime.Now;
if (d1.Subtract(d2).Seconds <= 1)
{
//consider these DateTimes equal... continue
}
I prefer to compare Datetime (as well as double) not with exact values but with value ranges, because it is quite unlikely that you have the exact value.
DateTime d1 = new DateTime(2011, 12, 27, 4, 37, 17);
DateTime d2 = DateTime.Now;
if ((d2 >= d1) && (d2 <= d1.AddMinutes(1)))
....
'simulate comparison of two datetimes
d1 = DateTime.Now
Threading.Thread.Sleep(250)
d2 = DateTime.Now
'see if two dates are within a second of each other
Dim ts As Double = ((d2 - d1).TotalSeconds)
If ts < 1 Then
'equal
Debug.WriteLine("EQ " & ts.ToString("n4"))
Else
Debug.WriteLine("neq " & ts.ToString("n4"))
End If
What is the Java equivalent of DateTime.Ticks in C#?
DateTime dt = new DateTime(2010, 9, 14, 0, 0, 0);
Console.WriteLine("Ticks: {0}", dt.Ticks);
What will be the equivalent of above mentioned code in Java?
Well, java.util.Date/Calendar only have precision down to the millisecond:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.MILLISECOND, 0); // Clear the millis part. Silly API.
calendar.set(2010, 8, 14, 0, 0, 0); // Note that months are 0-based
Date date = calendar.getTime();
long millis = date.getTime(); // Millis since Unix epoch
That's the nearest effective equivalent. If you need to convert between a .NET ticks value and a Date/Calendar you basically need to perform scaling (ticks to millis) and offsetting (1st Jan 1AD to 1st Jan 1970).
Java's built-in date and time APIs are fairly unpleasant. I'd personally recommend that you use Joda Time instead. If you could say what you're really trying to do, we can help more.
EDIT: Okay, here's some sample code:
import java.util.*;
public class Test {
private static final long TICKS_AT_EPOCH = 621355968000000000L;
private static final long TICKS_PER_MILLISECOND = 10000;
public static void main(String[] args) {
long ticks = 634200192000000000L;
Date date = new Date((ticks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND);
System.out.println(date);
TimeZone utc = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(utc);
calendar.setTime(date);
System.out.println(calendar);
}
}
Note that this constructs a Date/Calendar representing the UTC instant of 2019/9/14. The .NET representation is somewhat fuzzy - you can create two DateTime values which are the same except for their "kind" (but therefore represent different instants) and they'll claim to be equal. It's a bit of a mess :(
In Java is:
long TICKS_AT_EPOCH = 621355968000000000L;
long tick = System.currentTimeMillis()*10000 + TICKS_AT_EPOCH;
System.nanoTime() gives you nanoseconds in Java (since 1.6). You'll still need to shift/rescale, but no precision will be lost.
Base on Jon Skeet I developed this class
import java.util.Calendar;
import java.util.Date;
public class DateHelper {
private static final long TICKS_AT_EPOCH = 621355968000000000L;
private static final long TICKS_PER_MILLISECOND = 10000;
public static long getUTCTicks(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return (calendar.getTimeInMillis() * TICKS_PER_MILLISECOND) + TICKS_AT_EPOCH;
}
public static Date getDate(long UTCTicks){
return new Date((UTCTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND);
}
}
It works for me
And for those of us showing up trying to get the current number of ticks as defined by the UUID specification:
/**
Returns the current tick count.
Ticks are the number of 100 ns intervals since October 15, 1582
#return
*/
private static long getUtcNowTicks() {
final long UNIX_EPOCH_TICKS = 122192928000000000L; //Number of ticks from 10/16/1582 to 1/1/1970
Instant i = Clock.systemUTC().instant(); //get the current time
long ticks = UNIX_EPOCH_TICKS; // number of ticks as of 1/1/1970
ticks += i.getEpochSecond()*10000000; //number of whole seconds (converted to ticks) since 1/1/1970
ticks += i.getNano() / 100; //number of ticks since the start of the second
return ticks;
/*
Some interesting tick values
Date Ticks
========== ==================
10/15/1582 0 Start of UUID epoch; the date we switched to the Gregorian calendar)
1/01/1601 5748192000000000 Start of Windows epoch (start of 1st Gregorian 400-year cycle)
12/30/1899 100101312000000000 Start of Lotus 123, Excel, VB, COM, Delphi epoch
1/01/1900 100103040000000000 Start of SQL Server epoch
1/01/1970 122192928000000000 Start of UNIX epoch
1/01/2000 131659776000000000
1/01/2010 134815968000000000
1/01/2020 137971296000000000
1/19/2038 143714420469999999 UNIX Y2k38 problem (January 19, 2038 3:14:07 am)
*/
}
To convert .Net Ticks to millis in java use this :
static final long TICKS_PER_MILLISECOND = 10000;
long ticks = 450000000000L; // sample tick value
long millis = (ticks / TICKS_PER_MILLISECOND);
There are 10,000 ticks in a millisecond, and C# considers the beginning of time January 1, 0001 at midnight. Here's a one-liner which converts an Instant to ticks.
public static long toTicks(Instant i)
{
return Duration.between(Instant.parse("0001-01-01T00:00:00.00Z"), i).toMillis() * 10000;
}