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;
}
Related
I have an Outlook VSTO addin and I am doing search for resource calendar availability using the GetFreeBusy() API Calll which, given a date, will search over the next 28 days in 30 minute increments (by default) to determine which slots are free and which are busy. It works fine except I am struggling to figure out how to cope with the situation where a daylight savings time exists within that 28 day interval.
Here is my code:
using Microsoft.Office.Interop.Outlook;
string freeBusy = exchangeUser.GetFreeBusy(startDate, 30, true);
this gives me back a string like this that returns free / busy availability in 30 minute increments for 28 days.
0000000000000000202222222222000000000000000000000000000000000222222
this string is always 1344 characters long (48 slots per day * 28 days)
where each character represents a 30 minute slot and shows 0 if the time is free. I have the following parsing code that I took from this Microsoft article that returns an array of free time slots:
private IEnumerable<DateTime> ParseFreeBusy(string freeBusyString, DateTime startingDate)
{
var timeSlots = new List<DateTime>();
for (int i = 0; i < freeBusyString.Length; i++)
{
double slot = i * 30;
DateTime timeSlot = startingDate.Date.AddMinutes(slot);
bool isFree = freeBusy.Substring(i, 1) == "0";
if (isFree)
{
timeSlots.Add(timeSlot);
}
}
return timeSlots;
}
If I plug in October 25th as the start date when I look at the results every thing lines up perfectly up until November 2nd at 2AM (given daylight savings)
The root issue is that my naive code is simply increments and keeps adding 30 minutes for each entry since I am simply looping through each slot and doing this:
startingDate.Date.AddMinutes(slot);
I did a test and booked a calendar slot from 1AM - 2AM on November 2nd and this is what i get from GetFreeBusy() starting on that day
002222000...
so using the default loop above (remember, every character is a 30 min slot and 0 = free), this would translate to the following slot logic:
12L00 AM - free (0)
12:30 AM - free (0)
1L00 AM - booked (2)
1:30 AM - booked (2)
THESE NEXT TWO "booked" below is really representing the 2nd 1AM - 2AM since we roll the clocks back an hour
2:00 AM - booked (2)
2:30 AM - booked (2)
3:00 AM - free (0)
which is wrong as my code would show 2AM - 3AM booked when the "real" 2-3A AM is free. If my parsing was correct and handled this rollback, I would end up with this correct answer of:
12L00 AM - free (0)
12:30 AM - free (0)
1L00 AM - booked (2)
1:30 AM - booked (2)
IGNORE the second 1AM to 2AM as its already taken care of
2:00 AM - free (0)
2:30 AM - free (0)
3:00 AM - free (0)
What is interesting is that regardless of daylight savings, the resulting string is always 1344 characters long (I would have expected it to be shorter or longer on those months with daylight savings implications).
Does anyone have any experience with using outlook GetFreeBusy() and understand for how to deal with this situation when you hit a daily savings time slot?
I have been playing around with a few ideas like:
var tzInfo = TimeZoneInfo.Local;
if (tzInfo.IsAmbiguousTime(timeSlot))
{
//this would be a time to do something
}
or something like
DaylightTime daylightTime = tz.GetDaylightChanges(minStartTime.Year);
if (daylightTime.End == proposedTimeSlot)
{
daylightSavingsOffset = daylightSavingsOffset + ((daylightTime.Delta.Hours * 60) / meetingDuration);
}
but I am not completely sure what do with this once i detect the "special slots" and I can't find any documentation or recommendations around this situation.
Any suggestions?
What is interesting is that regardless of daylight savings, the resulting string is always 1344 characters long (I would have expected it to be shorter or longer on those months with daylight savings implications).
It's completely logical, Let's start with GetFreeBusy, It happens because the result is based on duration and specific intervals not Date and time stamps, and as we know Date and Time is relative to our location based on time zone but elapsed time and duration is not,let's assume we have meeting in 10 hours from now, we maybe are in different time Zones but after 10 hours (relative to our location) we both should meet each other, but our local times may vary significantly, the system works this way because it should be able to operate across different time zones at the same time, so it uses UniversalTime at the heart and converts it back to local time for generating the result.
Now let's check the code, when we use startingDate.Date.AddMinutes(slot); we are not considering DateTimeSaving as we are operating on our local time and the addition is relative to it, by using UniversalTime we can create a unified base point for our time additions and intervals, after that by converting it back to local time we can apply date time saving to it,
so I believe this code should work as expected:
private static IEnumerable<DateTime> ParseFreeBusy(string freeBusyString, DateTime startingDate)
{
var timeSlots = new HashSet<DateTime>();
var utc = startingDate.ToUniversalTime();
var timeZone = TimeZone.CurrentTimeZone; //can change to particular time zone, currently set to local timezone of the system
for (int i = 0; i < freeBusyString.Length; i++)
{
double slot = i * 30;
DateTime timeSlot = utc.AddMinutes(slot);
bool isFree = freeBusyString.Substring(i, 1) == "0";
if (isFree)
{
var localTimeSlot = timeZone.ToLocalTime(timeSlot);
timeSlots.Add(localTimeSlot);
}
}
return timeSlots;
}
NOTE:: beside using UTC for time, I changed the List to HashSet because if you have free slot on those specific times you would get duplicate entries, by using HashSet this problem won't occur.
here is a method I used for testing it:
private static void TestFreeSlots()
{
var saving = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year);
var datetime = new DateTime(saving.End.Year, saving.End.Month, saving.End.Day - 1);
//you may need to change the string to see effective result
var result = ParseFreeBusy("0000000000000000000000000000000000000000000000002222000", datetime);
}
and finally here is a little sample to demonstrate the method used here
private static void TestTimeZone()
{
var saving = TimeZone.CurrentTimeZone.GetDaylightChanges(DateTime.Now.Year);
var datetime = new DateTime(saving.End.Year, saving.End.Month, saving.End.Day - 1);
var utc = datetime.ToUniversalTime();
var timeZone = TimeZone.CurrentTimeZone;
for (var i = 0; i < 120; i++)
{
var next = timeZone.ToLocalTime(utc);
Console.WriteLine(next);
utc = utc.AddMinutes(30);
}
}
and your results should be similar to this:
This first function finds time slots that Outlook will return as duplicates due to DST. It can probably stand some refactoring but it's effective for now: (EDIT: I modified the function so it doesn't remove time slots as you go into DST).
public static Collection<DateTime> GetDuplicateSlots(
TimeZoneInfo timeZone, DateTime start, int intervalLength, int numOfIntervals)
{
Collection<DateTime> duplicates = new Collection<DateTime>();
bool dstAtStart = timeZone.IsDaylightSavingTime(start);
for (int interval = 0; interval < numOfIntervals; interval++)
{
DateTime current = start.Date.AddMinutes(interval * intervalLength);
if (dstAtStart && !timeZone.IsDaylightSavingTime(current))
{
duplicates.Add(current);
duplicates.Add(current.AddMinutes(intervalLength));
return duplicates;
}
}
return duplicates; // no duplicates
}
Then we just need to adjust for the duplicates when we go through the string of free/busy time slots:
public static void DisplayFreeBusy(
string freeBusyString, DateTime start, int intervalLength)
{
TimeZoneInfo cst = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
Collection<DateTime> duplicateSlots =
GetDuplicateSlots(cst, start, intervalLength, freeBusyString.Length);
int duplicatesConsumed = 0;
for (int slot = 0; slot < freeBusyString.Length; slot++)
{
int actualSlot = slot - duplicatesConsumed;
DateTime slotTime = start.Date.AddMinutes(actualSlot * intervalLength);
if (duplicatesConsumed != duplicateSlots.Count &&
duplicateSlots.Contains(slotTime))
{
duplicatesConsumed++;
}
else
{
Console.WriteLine("{0} -- {1}", slotTime, freeBusyString[slot]);
}
}
}
Note that the actualSlot variable corresponds to the time slots, while the slot variable still corresponds with a character in the free/busy string. When a duplicate is found, it is "consumed" and that character in the string is skipped. Once the duplicates have been consumed, the function will continue normally from that point.
I live in Arizona and we don't have DST so I had to force a different time zone. You can obviously substitute your local time zone instead of CST.
I tested this with a shorter input string but I added the extra '2' characters for the daylight savings slots. It handled the excess slots and prints out the proper number of slots.
In my system, I am storing a duration in Ticks, which is being passed to my client mobile application, and from there I want to convert ticks into a human readable form. In my case, days, hours and minutes.
My client mobile application is coded using Javascript, and so this is what I'm using to convert the duration to days/hours/minutes.
In C# .NET, a single tick represents one hundred nanoseconds, or one ten-millionth of a second. [Source].
Therefore, in order to calculate the number of days from the number of ticks (rounded to nearest whole numbers), I first calculate the number of seconds by multiplying by ten million, and then multiplying that by the number of seconds in a day (60 seconds in minute, 60 minutes in hour, 24 hours in day). I use the modulus operator (%) to get the remainder values that make up the duration of hours and minutes.
var time = 3669905128; // Time value in ticks
var days = Math.floor(time/(24*60*60*10000000)); // Math.floor() rounds a number downwards to the nearest whole integer, which in this case is the value representing the day
var hours = Math.round((time/(60*60*10000000)) % 24); // Math.round() rounds the number up or down
var mins = Math.round((time/(60*10000000)) % 60);
console.log('days: ' + days);
console.log('hours: ' + hours);
console.log('mins: ' + mins);
So, in the above example, the amount of ticks is equivalent to 6 minutes (rounded up).
And to take another example, with 2,193,385,800,000,000 ticks, we get 2538 days, 15 hours and 23 minutes.
var ticks = 635556672000000000;
//ticks are in nanotime; convert to microtime
var ticksToMicrotime = ticks / 10000;
//ticks are recorded from 1/1/1; get microtime difference from 1/1/1/ to 1/1/1970
var epochMicrotimeDiff = Math.abs(new Date(0, 0, 1).setFullYear(1));
//new date is ticks, converted to microtime, minus difference from epoch microtime
var tickDate = new Date(ticksToMicrotime - epochMicrotimeDiff);
According to this page the setFullYear method returns "A Number, representing the number of milliseconds between the date object and midnight January 1 1970".
Check out this page for all the methods from the javascript Date object.
You need to consider 2 things:
Resolution
Ticks in .Net's DateTime are 0.1 Microsecond, while Javascript counts Milliseconds.
Offset
In addition, .Net counts from 1.1.0000 while Javascript counts from 1.1.1970.
TeaFiles.Net has a Time class that uses Java = Javascript ticks. It has a scale property and a predefined Timescale.Java scale, that converts from .Net to Javascript.
At the server-side, you can use a extension method, like this:
public static class DateTimeExtensions {
private static readonly long UnixEpochTicks = (new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).Ticks;
public static long? ToJavascriptTicks(this DateTime? value) {
return value == null ? (long?)null : (value.Value.ToUniversalTime().Ticks - UnixEpochTicks) / 10000;
}
public static long ToJavascriptTicks(this DateTime value) {
return (value.ToUniversalTime().Ticks - UnixEpochTicks) / 10000;
}
}
With this extensions, you can get the javascript ticks, and then you simply pass them to the client-side.
If you are using MVC:
You have the ViewModel:
public class MyViewModel {
public long MyJsTicks { get; set; }
}
And the Controller:
public ActionResult Action() {
long myJsTicks = DateTime.UtcNow.ToJavascriptTicks(); //<-- use the extension method
MyViewModel viewModel = new MyViewModel();
viewModel.MyJsTicks = myJsTicks;
return View(viewModel);
}
At the client-side:
var jsticks = <the js ticks obtained from server-side>;
var mydatetime = new Date(jsticks);
If you are using Razor view engine for your mobile app, getting the calculated js ticks from the server-side in your view is extremely simple, using a in-line expression:
var jsticks = #(Model.MyJsTicks);
var mydatetime = new Date(jsticks);
Finally, to get days, hours and minutes from the javascript Date object:
var hours = mydatetime.getHours();
var minutes = mydatetime.getMinutes();
var seconds = mydatetime.getSeconds();
(as you can see in the javascript "Date" object reference: https://www.w3schools.com/jsref/jsref_obj_date.asp)
Let's make it simpler, shell we?....
according to microsoft:
public const long TicksPerDay = 864000000000;
https://learn.microsoft.com/en-us/dotnet/api/system.timespan.ticksperday?view=net-5.0
private int GetDaysDiff(DateTime fromDate, DateTime toDate)
{
long ticksPerDay = 864000000000;
long ticksDiff = Math.Abs(fromDate.Ticks - toDate.Ticks);
var days = ticksDiff / ticksPerDay;
return (int)days;
}
that's all folks!
long ticks = new DateTime(2012, 1, 31).ToLocalTime().Ticks; // 634635684000000000
But how to do this without DateTime constructor ?
edit
What I actually want is to keep only the years, months and days from the ticks.
long ALL_Ticks = DateTime.Now.Ticks; // 634636033446495283
long Only_YearMonthDay = 634635684000000000; // how to do this ?
I want to use this in a linq-sql query using Linq.Translations.
If you only want the ticks for the date portion of the current datetime you could use:
long Only_YearMonthDay = DateTime.Now.Date.Ticks; //634635648000000000
//DateTime.Now.Date.Ticks + DateTime.Now.TimeOfDay.Ticks == DateTime.Now.Ticks
You could find out how many days are in the calculation and then multiply by 864,000,000,000 (which is how many ticks are in a day). Is that what you are looking for? Bit of documentation here : http://msdn.microsoft.com/en-us/library/system.timespan.ticksperday.aspx.
Happy coding,
Cheers,
Chris.
OK - didn't think this through properly! Ticks represent the amount of 100 nanosecond intervals since 12:00:00 midnight, January 1, 0001. You would need to calculate how many days have passed since that date and then multiply it by the ticks per day value!
If I understand you right, you are not worried about the ticks up to a particular time of the day?! So, it would be something along the lines of :
var ticksToDate = (DateTime.UtcNow - DateTime.MinValue).Days * 864000000000;
Does that answer your question??
That is going to be rather difficult unless you have some other way of getting the current date and time. According to MSDN:
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001, which represents DateTime.MinValue. It does not include the number of ticks that are attributable to leap seconds.
Now, if you know the current date and time, you can calculate how many days have passed since January 1, 0001 and use that to calculate the number of ticks.
I understand you dont want the hour parts of the date. If you use Date, then you only get the day (for example: 01/01/2012 00:00:00)
long ticks = new DateTime(2012, 1, 31).Date.Ticks;
And with any DateTime object already created is the same of course.
long ticks = dateObject.Date.Ticks;
You already have the answer there in your post:
long ALL_Ticks = DateTime.Now.Ticks;
// that's the ticks (from DateTime.MinValue) until 'now' (this very moment)
long ticks = new DateTime(2012, 1, 31).ToLocalTime().Ticks;
// or
long ticks = DateTime.Now.Date.Ticks;
// that's the ticks until the beginning of today
long yearmonthticks = new DateTime(2012, 1, 1).ToLocalTime().Ticks;
// that's the ticks until the beginning of the month
// etc..., the rest is simple subtractions
Since your question doesn't specify any reason not to use the DateTime constructor, this is the best solution for what seems like your problem.
I had a use case where I couldn't use DateTime but needed Years/Months from Ticks.
I used the source behind DateTime to figure out how. To go the other way you can look at the constructor, one of which calls the following code.
private static long DateToTicks(int year, int month, int day) {
if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) {
int[] days = IsLeapYear(year)? DaysToMonth366: DaysToMonth365;
if (day >= 1 && day <= days[month] - days[month - 1]) {
int y = year - 1;
int n = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
return n * TicksPerDay;
}
}
throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
}
This can be found in link below, of course you will need to re-write to suit your needs and look up the constants and IsLeapYear function too.
https://referencesource.microsoft.com/#mscorlib/system/datetime.cs,602
I am trying to write a function that will convert a DateTime.Now instance to the number of seconds it represents so that I can compare that to another DateTime instance. Here is what I currently have:
public static int convertDateTimeToSeconds(DateTime dateTimeToConvert)
{
int secsInAMin = 60;
int secsInAnHour = 60 * secsInAMin;
int secsInADay = 24 * secsInAnHour;
double secsInAYear = (int)365.25 * secsInADay;
int totalSeconds = (int)(dateTimeToConvert.Year * secsInAYear) +
(dateTimeToConvert.DayOfYear * secsInADay) +
(dateTimeToConvert.Hour * secsInAnHour) +
(dateTimeToConvert.Minute * secsInAMin) +
dateTimeToConvert.Second;
return totalSeconds;
}
I realize that I am truncating the calculation for seconds in a year, but I don't need my calculation to be precise. I'm really looking to know if the method that I am using to calculate seconds is correct.
Does anyone have anything that could better compute seconds given from a DateTime object?
Also, Should the return type be int64 if I am coding in C# if I am going to calculate all the seconds since 0 AD?
The DateTime type supports comparison operators:
if (dateTimeA > dateTimeB)
{
...
This also works for DateTime values returned by DateTime.AddSeconds:
if (dateTimeA.AddSeconds(42) > dateTimeB)
{
...
If you really want the number of seconds that elapsed since 01/01/0001 00:00:00, you can calculate the difference between the two DateTime values. The resulting TimeSpan value has a TotalSeconds property:
double result = DateTime.Now.Subtract(DateTime.MinValue).TotalSeconds;
It really doesn't make sense to convert a DateTime object to seconds. Seconds only make sense if you are dealing with a length of time (TimeSpan). Should you want to compare two dates to get the number of seconds between them:
TimeSpan diff = DateTime.Now - PreviousDateTime;
double seconds = diff.TotalSeconds;
If the purpose is finding the number of seconds between two dates, you'd be much better off using the TimeSpan object.
TimeSpan span = date2 - date1;
double seconds = span.TotalSeconds;
See suggestion from thread below:
How do I convert ticks to minutes?
TimeSpan.FromTicks(DateTime.Now.Ticks).TotalSeconds;
Assuming you really need to get at the seconds for the datetime object, you could directly get the "Ticks" property from it. These aren't in seconds but you can easily divide by the proper factor to convert the Ticks to seconds.
See: http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx
So, something like:
DateTime.Now.Ticks/TimeSpan.TicksPerSecond
If you want to compare 2 DateTime object, why just not use the provided operators?
http://msdn.microsoft.com/en-us/library/aa326723%28v=VS.71%29.aspx
DateTime a, b;
if (a > b) //a is after b
I would use the TimeSpan class to get the exact difference between two DateTime instances. Here is an example:
DateTime dt1 = DateTime.Now;
DateTime dt2 = new DateTime(2003,4,15);
TimeSpan ts = dt1.Subtract(dt2);
Once the TimeSpan value (ts, in the code snippet above) is available, you can examine its values to correctly convert the TimeSpan to a given number of seconds.
Using a TimeSpan to get the elapsed time between two DateTimes is probably the best way to go but if you really want to get the number of seconds for a given DateTime you could do something like the following:
DateTime dateTimeToConvert = DateTime.Now;
TimeSpan tsElapsed = dateTimeToConvert - DateTime.MinValue;
return tsElapsed.TotalSeconds;
Note that tsElapsed.TotalSeconds is a Double, not an Int.
Do note that the goal is to get the number of seconds since DateTime.MinVal (the first day of the calendar). I say this, because I see all of these answers for "you do time comparisons like this... add in the object, multiply by that object and do cross-calculus on them, divide by the quotient of the summed result, and Boom! not what you asked."
There's a really simple answer here. Ticks are 100-nanosecond increments. DateTime object.Ticks is the number of ticks that have occurred since 1/1/0001. Ie, year zero. There are 10 million nanoseconds in a second. so...
public static long convertDateTimeToSeconds(DateTime dateTimeToConvert) {
// According to Wikipedia, there are 10,000,000 ticks in a second, and Now.Ticks is the span since 1/1/0001.
long NumSeconds= dateTimeToConvert.Ticks / 10000000;
return NumSeconds;
}
I need to round-off the hours based on the minutes in a DateTime variable. The condition is: if minutes are less than 30, then minutes must be set to zero and no changes to hours, else if minutes >=30, then hours must be set to hours+1 and minutes are again set to zero. Seconds are ignored.
example:
11/08/2008 04:30:49 should become 11/08/2008 05:00:00
and 11/08/2008 04:29:49 should become 11/08/2008 04:00:00
I have written code which works perfectly fine, but just wanted to know a better method if could be written and also would appreciate alternative method(s).
string date1 = "11/08/2008 04:30:49";
DateTime startTime;
DateTime.TryParseExact(date1, "MM/dd/yyyy HH:mm:ss", null,
System.Globalization.DateTimeStyles.None, out startTime);
if (Convert.ToInt32((startTime.Minute.ToString())) > 29)
{
startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}",
startTime.Month.ToString(), startTime.Day.ToString(),
startTime.Year.ToString(), startTime.Hour.ToString(), "00", "00"));
startTime = startTime.Add(TimeSpan.Parse("01:00:00"));
Console.WriteLine("startTime is :: {0}",
startTime.ToString("MM/dd/yyyy HH:mm:ss"));
}
else
{
startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}",
startTime.Month.ToString(),
startTime.Day.ToString(), startTime.Year.ToString(),
startTime.Hour.ToString(), "00", "00"));
Console.WriteLine("startTime is :: {0}",
startTime.ToString("MM/dd/yyyy HH:mm:ss"));
}
Just as an alternative:
public static DateTime Round( DateTime dateTime )
{
var updated = dateTime.AddMinutes( 30 );
return new DateTime( updated.Year, updated.Month, updated.Day,
updated.Hour, 0, 0, dateTime.Kind );
}
If speed is an issue, the following should be the fastest way:
static DateTime RoundToHour(DateTime dt){
long ticks = dt.Ticks + 18000000000;
return new DateTime(ticks - ticks % 36000000000, dt.Kind);
}
It's also a pretty straight-forward and simple way to do it.
To explain, a DateTime structure doesn't actually have fields that store the year, month, day, hour, minute, etc. It stores one single long value, the number of "ticks" since a certain epoch (Jan 1, 1 AD). A tick is 100 nanoseconds, or one 10,000,000th of a second.
Any time you use any of the date/time properties, it divides by the proper constant.
So here, we add a constant equal to 30 minutes (30 * 60 * 1e7 = 18000000000 ticks), then subtract the remainder after dividing by a constant equal to one hour (60 * 60 * 1e7 = 36000000000 ticks).
What about:
public static DateTime RoundToHours(DateTime input)
{
DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
if (input.Minute > 29)
return dt.AddHours(1);
else
return dt;
}
No need to convert to string and back again!
EDIT:
Using a input.Hour+1 in the constructor will fail if the Hour is 23. The .AddHours(1) will correctly result in '0:00' the next day.
Here goes!
var rounded = date.AddMinutes(30).Date.AddHours(date.AddMinutes(30).Hour);
And for those that want it floored
var floored = date.Date.AddHours(date.Hours)
DateTime s = DateTime.Now;
if (s.Minute > 30) s = s.AddHours(1); //only add hours if > 30
if (s.Minute == 30 && s.Second > 0) s = s.AddHours(1); //add precision as needed
s = new DateTime(s.Year, s.Month, s.Day, s.Hour, 0, 0);
Extending Hans Kestings good Answer:
public DateTime RoundToHours(DateTime input)
{
DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0);
return dt.AddHours((int)(input.Minutes / 30));
}
The (int) Cast might not be required.
EDIT: Adapted the corrections Hans Kesting made in his Answer.
To improve upon some of the other methods, here is a method that will also preserve the DateTime Kind:
/// <summary>
/// Rounds a DateTime to the nearest hour.
/// </summary>
/// <param name="dateTime">DateTime to Round</param>
/// <returns>DateTime rounded to nearest hour</returns>
public static DateTime RoundToNearestHour(this DateTime dateTime)
{
dateTime += TimeSpan.FromMinutes(30);
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, 0, 0, dateTime.Kind);
}
Based on P Daddy's solution, I propose to not hardcode that big number of ticks to one hour. Hardcoding is evil, isn't it? With this modified solution, you can now round any given time to any number of minutes:
public DateTime RoundToMinutes(DateTime dt, int NrMinutes)
{
long TicksInNrMinutes = (long)NrMinutes * 60 * 10000000;//1 tick per 100 nanosecond
long ticks = dt.Ticks + TicksInNrMinutes / 2;
return new DateTime(ticks - ticks % TicksInNrMinutes, dt.Kind);
}
I use this for rounding to the nearest 5 minutes, e.g. 22:23 becomes 22:25.
Years ago I used the same method to round amounts of money to the nearest 25 cent, e.g. $ 22.23 becomes $ 22.25. But the project manager sometimes changed his mind, but changing the rounding to the nearest 10 or 5 cent would be trivial. So now I similarly do not have to get nervous when my project mgr wants rounding times to another round nr of minutes.
So this rounding method is both fast, and flexible.
My method was already found and published in this 2008 SO solution
DateTime dtm = DateTime.Now;
if (dtm.Minute < 30)
{
dtm = dtm.AddMinutes(dtm.Minute * -1);
}
else
{
dtm = dtm.AddMinutes(60 - dtm.Minute);
}
dtm = dtm.AddSeconds(dtm.Second * -1);