25

I have a "requirement" to give a timestamp to the nearest second... but NOT more accurate than that. Rounding or truncating the time is fine.

I have come up with this abomination

 dateTime = DateTime.Parse(DateTime.UtcNow.ToString("U"));

(U is the Long format date and time. "03 January 2007 17:25:30")

Is there some less horrific way of achieving this?

Edit: So from the linked truncate milliseconds answer (thanks John Odom) I am going to do this

 private static DateTime GetCurrentDateTimeNoMilliseconds()
        {
            var currentTime = DateTime.UtcNow;
            return new DateTime(currentTime.Ticks - (currentTime.Ticks % TimeSpan.TicksPerSecond), currentTime.Kind);
        }

barely less horrific.. but it does preserve the 'kind' of datetime which I do care about. My solution did not.

Loofer
  • 6,841
  • 9
  • 61
  • 102
  • 1
    Are you sure that this is C? – devnull Feb 11 '14 at 14:29
  • This is definitely not `C` – Ivaylo Strandjev Feb 11 '14 at 14:29
  • This has nothing to do with C. What language are you working in? In C you can always use `time`/`ctime`. – Sergey L. Feb 11 '14 at 14:29
  • 1
    This looks like C#, I believe you should change your tag to C# if you are actually working in C#. Also have you checked this link? [http://stackoverflow.com/questions/1004698/how-to-truncate-milliseconds-off-of-a-net-datetime](http://stackoverflow.com/questions/1004698/how-to-truncate-milliseconds-off-of-a-net-datetime) Also, do you mean you wanted to return DateTime rounded to nearest second or the total seconds? – John Odom Feb 11 '14 at 14:31
  • Do you need to round or truncate to the second? _"Nearest"_ suggests that you need the former. – Tim Schmelter Feb 11 '14 at 14:41
  • 1
    Sorry of course this is c#. – Loofer Feb 11 '14 at 15:09

7 Answers7

54

You could implement this as an extension method that allows you to trim a given DateTime to a specified accuracy using the underlying Ticks:

public static DateTime Trim(this DateTime date, long ticks) {
   return new DateTime(date.Ticks - (date.Ticks % ticks), date.Kind);
}

Then it is easy to trim your date to all kinds of accuracies like so:

DateTime now = DateTime.Now;
DateTime nowTrimmedToSeconds = now.Trim(TimeSpan.TicksPerSecond);
DateTime nowTrimmedToMinutes = now.Trim(TimeSpan.TicksPerMinute);
Jesse Carter
  • 20,062
  • 7
  • 64
  • 101
13

You can use this constructor:

public DateTime(
    int year,
    int month,
    int day,
    int hour,
    int minute,
    int second
)

so it would be:

DateTime dt = DateTime.Now;
DateTime secondsDt = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
w.b
  • 11,026
  • 5
  • 30
  • 49
8

If you really want to round the time to the nearest second, you can use:

DateTime.MinValue
        .AddSeconds(Math.Round((DateTime.Now - DateTime.MinValue).TotalSeconds));

However unless that extra half a second really makes a difference, you can just remove the millisecond portion:

DateTime.Now.AddTicks( -1 * (DateTime.Now.Ticks % TimeSpan.TicksPerSecond));
kasperhj
  • 10,052
  • 21
  • 63
  • 106
D Stanley
  • 149,601
  • 11
  • 178
  • 240
1

Try this

TimeSpan span= dateTime.Subtract(new DateTime(1970,1,1,0,0,0, DateTimeKind.Utc));
return span.TotalSeconds;
Sadique
  • 22,572
  • 7
  • 65
  • 91
1

After working with the selected solution I am satisfied that it works well. However the implementations of the extension methods posted here do not offer any validation to ensure the ticks value you pass in is a valid ticks value. They also do not preserve the DateTimeKind of the DateTime object being truncated. (This has subtle but relevant side effects when storing to a database like MongoDB.)

If the true goal is to truncate a DateTime to a specified value (i.e. Hours/Minutes/Seconds/MS) I recommend implementing this extension method in your code instead. It ensures that you can only truncate to a valid precision and it preserves the important DateTimeKind metadata of your original instance:

public static DateTime Truncate(this DateTime dateTime, long ticks)
{
    bool isValid = ticks == TimeSpan.TicksPerDay 
        || ticks == TimeSpan.TicksPerHour 
        || ticks == TimeSpan.TicksPerMinute 
        || ticks == TimeSpan.TicksPerSecond 
        || ticks == TimeSpan.TicksPerMillisecond;

    // https://stackoverflow.com/questions/21704604/have-datetime-now-return-to-the-nearest-second
    return isValid 
        ? DateTime.SpecifyKind(
            new DateTime(
                dateTime.Ticks - (dateTime.Ticks % ticks)
            ),
            dateTime.Kind
        )
        : throw new ArgumentException("Invalid ticks value given. Only TimeSpan tick values are allowed.");
}

Then you can use the method like this:

DateTime dateTime = DateTime.UtcNow.Truncate(TimeSpan.TicksPerMillisecond);

dateTime.Kind => DateTimeKind.Utc
Kyle L.
  • 594
  • 4
  • 26
0

Here is a rounding method that rounds up or down to the nearest second instead of just trimming:

public static DateTime Round(this DateTime date, long ticks = TimeSpan.TicksPerSecond) {
    if (ticks>1)
    {
        var frac = date.Ticks % ticks;
        if (frac != 0)
        {
            // Rounding is needed..
            if (frac*2 >= ticks)
            {
                // round up
                return new DateTime(date.Ticks + ticks - frac);
            }
            else
            {
                // round down
                return new DateTime(date.Ticks - frac);
            }
        }
    }
    return date;
}

It can be used like this:

DateTime now = DateTime.Now;
DateTime nowTrimmedToSeconds = now.Round(TimeSpan.TicksPerSecond);
DateTime nowTrimmedToMinutes = now.Round(TimeSpan.TicksPerMinute);
0

Here is an extension method for rounding the dates to the arbitrary interval specified as TimeSpan:

public static DateTime RoundTo(this DateTime date, TimeSpan timeSpan)
{
    if (timeSpan.Ticks == 0)
    {
        throw new ArgumentException("Cannot round to zero interval", nameof(timeSpan));
    }

    var ticks =
        Math.Round((double)date.Ticks / timeSpan.Ticks, MidpointRounding.AwayFromZero)
        * timeSpan.Ticks;
    return new DateTime((long)ticks, date.Kind);
}

Examples:

DateTime.UtcNow.RoundTo(TimeSpan.FromSeconds(1));
DateTime.UtcNow.RoundTo(TimeSpan.FromSeconds(15));
DateTime.UtcNow.RoundTo(TimeSpan.FromMinutes(1));

Example in .NET Fiddle