3

Assume I have a DateTime:

    DateTime datetime(2013,11,08,17,45,23,300);//2013:11:08 17:45:23:300

I want to truncate this DateTime by differenct accuracy and return the minimum DateTime like this:

    Year:         2013:01:01 00:00:00:000      
    Quarter:      2013:10:01 00:00:00:000    //Oct is first month of that quarter 
    Month:        2013:11:01 00:00:00:000
    Week:         2013:11:03 00:00:00:000    // 3rd is Sunday of that week
    Day:          2013:11:08 00:00:00:000
    Hours         2013:11:08 17:00:00:000   
    Minute:       2013:11:08 17:45:00:000   
    Second:       2013:11:08 17:45:23:000   

I know you can do it by changing different part of the DateTime, is there a better way to do it? or is there already a build in function in .net which I don't know?

diwatu
  • 5,641
  • 5
  • 38
  • 61
  • 1
    Can I add a simple comment. On quarter, wouldn't the year be `2012`? As for the question what is the `Regular` way? – Nico Jan 07 '14 at 22:38
  • Possible duplicate of [Is there a better way in C# to round a DateTime to the nearest 5 seconds?](http://stackoverflow.com/questions/766626/is-there-a-better-way-in-c-sharp-to-round-a-datetime-to-the-nearest-5-seconds), there is an answer with generic `DateTime` rounding method. – Konrad Kokosa Jan 07 '14 at 22:39
  • @KonradKokosa Pretty sure this is different. This question is about printing all the different parts without doing each by hand. Perhaps with a custom format – Gary.S Jan 07 '14 at 22:41
  • "Better" in what way? – Jon Jan 07 '14 at 22:42
  • Before I asked the question I already read that one, I don't feel they are close. Thanks – diwatu Jan 07 '14 at 22:43
  • There is a difference between cases. Stuff like "day", "hour", "minute", and so on, can be done mathematically, for example by truncating the number of ticks down to the nearest smaller multiple of how many ticks go into a "day", "hour", etc. So these are very easy to make an extension method for that takes in the `DateTime` as the `this` parameter and a `TimeSpan` parameter to specify the number of ticks in the desired resolution. However cases like nearest quarter must be done differently. – Jeppe Stig Nielsen Jan 07 '14 at 23:00

3 Answers3

4

There's not one that I know of, but this should do the trick:

public enum Accuracy { Year, Quarter, Month, Week, Day, Hour, Minute, Second};

private static DateTime TruncateDate(DateTime inDate, Accuracy accuracy){
        switch (accuracy)
        {
            case Accuracy.Year:
                return new DateTime(inDate.Year, 1, 1);
            case Accuracy.Quarter:
                int i = inDate.Month % 3;
                return new DateTime(inDate.Year, inDate.Month - i + 1, 1);
            case Accuracy.Month:
                return new DateTime(inDate.Year, inDate.Month, 1);
            case Accuracy.Week:
                return new DateTime(inDate.Year, inDate.Month, inDate.Day).AddDays(-(int)inDate.DayOfWeek);
            case Accuracy.Day:
                return new DateTime(inDate.Year, inDate.Month, inDate.Day);
            case Accuracy.Hour:
                return new DateTime(inDate.Year, inDate.Month, inDate.Day, inDate.Hour, 0, 0);
            case Accuracy.Minute:
                return new DateTime(inDate.Year, inDate.Month, inDate.Day, inDate.Hour, inDate.Minute, 0);
            case Accuracy.Second:
                return new DateTime(inDate.Year, inDate.Month, inDate.Day, inDate.Hour, inDate.Minute, inDate.Second);
            default:
                throw new ArgumentOutOfRangeException("accuracy");
        }
    }

Edit: corrected for when Sunday is in a different month.

Xinbi
  • 272
  • 1
  • 2
  • 10
  • 1
    +1: looks like reasonable starting point. Obviously "first day of the week" is culture specific and there could be different rules for "year"/"financial year"/"quoter"... – Alexei Levenkov Jan 07 '14 at 22:58
  • Thanks,good code. One little thing is you can cast the dayofweek to int just like (int)inDate.DayofWeek – diwatu Jan 07 '14 at 22:58
  • You're going to lose the `DateTimeKind` of the date (ie, UTC or Local) unless you specify that as well. – Brian Reischl Jan 07 '14 at 23:05
  • I found something is very complicated, when a day and it's Sunday are across difference month, it is hard to deal with – diwatu Jan 07 '14 at 23:14
  • True that. Try this instead: `new DateTime(inDate.Year, inDate.Month, inDate.Day).AddDays(-(int)inDate.DayOfWeek);` – Xinbi Jan 07 '14 at 23:21
3

Based on my own comment:

public static DateTime Truncate(this DateTime dt, TimeSpan resolution)
{
  return new DateTime(dt.Ticks - dt.Ticks % resolution.Ticks);
}

Edit:

Example use: var truncated = dt.Truncate(Timespan.FromHours(1.0));

As I said in that comment, this is not useful for stuff like years and quarters of a year whose lengths (mathematically) vary from instance to instance.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • how ddi you define the resolution? – diwatu Jan 07 '14 at 23:16
  • I like this solution but for week and above it does not give the desired result. – Magnus Jan 07 '14 at 23:19
  • @Magnus Regarding weeks, they do have a fixed length, of 7*24 hours. If you use my methods with weeks, it becomes important what day of week was the date 01/Jan/0001 in the proleptic Gregorian calendar. Surely the same as 01/Jan/2001, and that was ***Monday***. Hopefully all cultures of the world can agree that Monday is the first day of the week(!). – Jeppe Stig Nielsen Jan 07 '14 at 23:32
  • Yeh, to bad we don't all agree, but it can be found in: `CurrentCulture.DateTimeFormat.FirstDayOfWeek` – Magnus Jan 07 '14 at 23:54
0

This creates a DateTime at midnight of Today. You can take any DateTime and call the 'Date' property to get rid of hours/minutes/seconds.

// 1/7/2014 12:00:00 AM
DateTime.Now.Date

From there to get a specific time like 5AM

var 5amDate = DateTime.Now.Date.AddHours(5)
// 1/7/2014 5:00:00 AM
SlaterCodes
  • 1,139
  • 10
  • 21