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;
}
Related
What I want to do is basically in the question title.
This is what I've tried so far, unsuccessfully.
Note that I haven't implemented exact hour and minute yet (9:30 pm).
It actually seems to always return a value between 00:00:59 and 00:00:01 for some reason
DateTime nextSunday = DateTime.Today.AddDays(((int)DayOfWeek.Sunday - (int)DateTime.Today.DayOfWeek + 7) % 7) + new TimeSpan(21, 30, 0);
TimeSpan untilNextSunday = nextSunday - DateTime.Now;
await ReplyAsync($"It is in **{TimeSpan.FromSeconds(untilNextSunday.Seconds)}**");
Which equals to
var today = DateTime.Today;
var daysUntilSunday = ((int)DayOfWeek.Sunday - (int)today.DayOfWeek + 7) % 7;
var nextSunday = today.AddDays(daysUntilSunday);
var ts = new TimeSpan(21, 30, 0);
nextSunday = nextSunday.Date + ts;
TimeSpan untilNextSunday = nextSunday - DateTime.Now;
If possible, I'd also like to use Paris TimeZone.
I tend to find all of the DateTime.Today.AddDays(((int)DayOfWeek.Sunday - (int)DateTime.Today.DayOfWeek + 7) % 7) + new TimeSpan(21, 30, 0) arithmetic quite confusing. Instead I try to go with a more iterative approach that can be clearly reasoned about.
Try this:
public static DateTime GetNextDateTime(DateTime now, DayOfWeek targetDay, TimeSpan targetTime)
{
DateTime target = now.Date.Add(targetTime);
while (target < now || target.DayOfWeek != targetDay)
{
target = target.AddDays(1.0);
}
return target;
}
Now you can use it like this:
DateTime now = DateTime.Now;
DateTime target = GetNextDateTime(DateTime.Now, DayOfWeek.Sunday, new TimeSpan(21, 30, 0));
TimeSpan untilNextSunday = target.Subtract(now);
Here's an example using Noda Time, including time zone handling. It doesn't attempt to handle "interesting" situations where (say) you ask for the next 1:30am, and it's already 1:45am but the clock goes back at 2am - in which case the right answer is really "45 minutes" but this code will give you a week instead.
using System;
using NodaTime;
class Test
{
static void Main()
{
var duration = GetDurationToNext(
IsoDayOfWeek.Sunday, new LocalTime(21, 30),
DateTimeZoneProviders.Tzdb["Europe/Paris"],
SystemClock.Instance);
Console.WriteLine($"Duration: {duration}");
}
static Duration GetDurationToNext(
IsoDayOfWeek dayOfWeek,
LocalTime timeOfDay,
DateTimeZone zone,
IClock clock) // Or just take an instant
{
var now = clock.GetCurrentInstant();
var localNow = now.InZone(zone).LocalDateTime;
var localNext = localNow
.Date.With(DateAdjusters.NextOrSame(dayOfWeek))
.At(timeOfDay);
// Handle "we're already on the right day-of-week, but
// later in the day"
if (localNext <= localNow)
{
localNext = localNext.PlusWeeks(1);
}
var zonedNext = localNext.InZoneLeniently(zone);
var instantNext = zonedNext.ToInstant();
return instantNext - now;
}
}
I want to get the first day and last day of the month where a given date lies in. The date comes from a value in a UI field.
If I'm using a time picker I could say
var maxDay = dtpAttendance.MaxDate.Day;
But I'm trying to get it from a DateTime object. So if I have this...
DateTime dt = DateTime.today;
How to get first day and last day of the month from dt?
DateTime structure stores only one value, not range of values. MinValue and MaxValue are static fields, which hold range of possible values for instances of DateTime structure. These fields are static and do not relate to particular instance of DateTime. They relate to DateTime type itself.
Suggested reading: static (C# Reference)
UPDATE: Getting month range:
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
UPDATE: From comments (#KarlGjertsen & #SergeyBerezovskiy)
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddSeconds(-1);
//OR
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddTicks(-1);
This is more a long comment on #Sergey and #Steffen's answers. Having written similar code myself in the past I decided to check what was most performant while remembering that clarity is important too.
Result
Here is an example test run result for 10 million iterations:
2257 ms for FirstDayOfMonth_AddMethod()
2406 ms for FirstDayOfMonth_NewMethod()
6342 ms for LastDayOfMonth_AddMethod()
4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
4160 ms for LastDayOfMonth_NewMethod()
4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
2491 ms for LastDayOfMonth_SpecialCase()
Code
I used LINQPad 4 (in C# Program mode) to run the tests with compiler optimization turned on. Here is the tested code factored as Extension methods for clarity and convenience:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
{
return value.Date.AddDays(1 - value.Day);
}
public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
{
return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
}
public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
{
return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
}
public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
{
return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
}
public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
void Main()
{
Random rnd = new Random();
DateTime[] sampleData = new DateTime[10000000];
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
}
GC.Collect();
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
}
string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
}
string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
}
string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
}
string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
}
string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();
for(int i = 0; i < sampleData.Length; i++) {
sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
}
GC.Collect();
sw.Restart();
for(int i = 0; i < sampleData.Length; i++) {
DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
}
string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();
}
Analysis
I was surprised by some of these results.
Although there is not much in it the FirstDayOfMonth_AddMethod was slightly faster than FirstDayOfMonth_NewMethod in most runs of the test. However, I think the latter has a slightly clearer intent and so I have a preference for that.
LastDayOfMonth_AddMethod was a clear loser against LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethod and LastDayOfMonth_NewMethodWithReuseOfExtMethod. Between the fastest three there is nothing much in it and so it comes down to your personal preference. I choose the clarity of LastDayOfMonth_NewMethodWithReuseOfExtMethod with its reuse of another useful extension method. IMHO its intent is clearer and I am willing to accept the small performance cost.
LastDayOfMonth_SpecialCase assumes you are providing the first of the month in the special case where you may have already calculated that date and it uses the add method with DateTime.DaysInMonth to get the result. This is faster than the other versions, as you would expect, but unless you are in a desperate need for speed I don't see the point of having this special case in your arsenal.
Conclusion
Here is an extension method class with my choices and in general agreement with #Steffen I believe:
public static class DateTimeDayOfMonthExtensions
{
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static int DaysInMonth(this DateTime value)
{
return DateTime.DaysInMonth(value.Year, value.Month);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, value.DaysInMonth());
}
}
If you have got this far, thank you for time! Its been fun :¬). Please comment if you have any other suggestions for these algorithms.
Getting month range with .Net API (just another way):
DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
"Last day of month" is actually "First day of *next* month, minus 1". So here's what I use, no need for "DaysInMonth" method:
public static DateTime FirstDayOfMonth(this DateTime value)
{
return new DateTime(value.Year, value.Month, 1);
}
public static DateTime LastDayOfMonth(this DateTime value)
{
return value.FirstDayOfMonth()
.AddMonths(1)
.AddMinutes(-1);
}
NOTE:
The reason I use AddMinutes(-1), not AddDays(-1) here is because usually you need these date functions for reporting for some date-period, and when you build a report for a period, the "end date" should actually be something like Oct 31 2015 23:59:59 so your report works correctly - including all the data from last day of month.
I.e. you actually get the "last moment of the month" here. Not Last day.
OK, I'm going to shut up now.
DateTime dCalcDate = DateTime.Now;
dtpFromEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, 1);
dptToEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, DateTime.DaysInMonth(dCalcDate.Year, dCalcDate.Month));
Here you can add one month for the first day of current month than delete 1 day from that day.
DateTime now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
If you only care about the date
var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind).AddMonths(1).AddDays(-1);
If you want to preserve time
var firstDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind).AddMonths(1).AddDays(-1);
Try this one:
string strDate = DateTime.Now.ToString("MM/01/yyyy");
The accepted answer here does not take into account the Kind of the DateTime instance. For example if your original DateTime instance was a UTC Kind then by making a new DateTime instance you will be making an Unknown Kind instance which will then be treated as local time based on server settings. Therefore the more proper way to get the first and last date of the month would be this:
var now = DateTime.UtcNow;
var first = now.Date.AddDays(-(now.Date.Day - 1));
var last = first.AddMonths(1).AddTicks(-1);
This way the original Kind of the DateTime instance is preserved.
I used this in my script(works for me) but I needed a full date without the need of trimming it to only the date and no time.
public DateTime GetLastDayOfTheMonth()
{
int daysFromNow = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) - (int)DateTime.Now.Day;
return DateTime.Now.AddDays(daysFromNow);
}
For Persian culture
PersianCalendar pc = new PersianCalendar();
var today = pc.GetDayOfMonth(DateTime.Now);
var firstDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddDays(-(today-1)));
var lastDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddMonths(1).AddDays(-today));
Console.WriteLine("First day "+ firstDayOfMonth);
Console.WriteLine("Last day " + lastDayOfMonth);
You can do it
DateTime dt = DateTime.Now;
DateTime firstDayOfMonth = new DateTime(dt.Year, date.Month, 1);
DateTime lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
Give this a try. It basically calculates the number of days that has passed on DateTime.Now, then subtracts one from that and uses the new value to find the first of the current month. From there it uses that DateTime and uses .AddMonths(-1) to get the first of the previous month.
Getting the last day of last month does basically the same thing except it adds one to number of days in the month and subtracts that value from DateTime.Now.AddDays, giving you the last day of the previous month.
int NumberofDays = DateTime.Now.Day;
int FirstDay = NumberofDays - 1;
int LastDay = NumberofDays + 1;
DateTime FirstofThisMonth = DateTime.Now.AddDays(-FirstDay);
DateTime LastDayOfLastMonth = DateTime.Now.AddDays(-LastDay);
DateTime CheckLastMonth = FirstofThisMonth.AddMonths(-1);
You can try this for get current month first day;
DateTime.Now.AddDays(-(DateTime.Now.Day-1))
and assign it a value.
Like this:
dateEndEdit.EditValue = DateTime.Now;
dateStartEdit.EditValue = DateTime.Now.AddDays(-(DateTime.Now.Day-1));
Create an instance of DateTime class
DateTime dateTime = DateTime.Now;
If you want to get the last day of the month you can do this
int lastDayOfMonth = DateTime.DaysInMonth(caducidadPuntos.Year, caducidadPuntos.Month);
If you want to get the first day of the month, you can do this
DateTime firstDayMonth = new DateTime(dateTime.Year, dateTime.Month, 1);
We had the requirement of being able to get the start and end of a given dates month, including times, inclusively. We ended up utilizing the aforementioned solutions, huge thanks to everyone here, and combined it into a util class to be able to get the start and end for a given month and year number combination up to the last millisecond. Including what we moved forward with in the event it helps someone else.
The util:
public class DateUtil
{
public static (DateTime startOfMonth, DateTime endOfMonth) GetStartAndEndOfMonth(int month, int year)
{
DateTime startOfMonth = GetStartOfMonth(month, year);
DateTime endOfMonth = GetEndOfMonth(month, year);
return (startOfMonth, endOfMonth);
}
public static DateTime GetStartOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date;
}
public static DateTime GetEndOfMonth(int month, int year)
{
return new DateTime(year, month, 1).Date.AddMonths(1).AddMilliseconds(-1);
}
}
Usage:
(DateTime startOfMonth, DateTime endOfMonth) = DateUtil.GetStartAndEndOfMonth(2, 2021); // February, 2021
easy way to do it
Begin = new DateTime(DateTime.Now.Year, DateTime.Now.Month,1).ToShortDateString();
End = new DataFim.Text = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)).ToShortDateString();
DateTime dCalcDate = DateTime.Now;
var startDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), 1);
var endDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), DateTime.DaysInMonth((Convert.ToInt32(Year)), Convert.ToInt32(Month)));
Im trying to perform a check is entered time inside specified time interval but Im stuck... I have one main block and another class which perform the check is the entered time inside the interval but I keep getting "No overload for method 'IsBetween' takes 0 arguments" when I try to call the method and get simple bool true or false, I know that solution is probably really simple but I just cant figure it out... :
static void Main()
{
var currentTime = Console.ReadLine();
DateTime now = Convert.ToDateTime(currentTime);
var dateNow = DateTime.Now;
var startTime = new DateTime(dateNow.Year, dateNow.Month, dateNow.Day, 13, 0, 0);
var endTime = new DateTime(dateNow.Year, dateNow.Month, dateNow.Day, 3, 0, 0);
}
This is my class for check :
public static class TimeExtensions
{
public static bool IsBetween(this DateTime now, DateTime startTime, DateTime endTime)
{
if (now.TimeOfDay == startTime.TimeOfDay) return true;
if (now.TimeOfDay == endTime.TimeOfDay) return true;
if (startTime.TimeOfDay <= endTime.TimeOfDay)
return (now.TimeOfDay >= startTime.TimeOfDay && now.TimeOfDay <= endTime.TimeOfDay);
else
return !(now.TimeOfDay >= endTime.TimeOfDay && now.TimeOfDay <= startTime.TimeOfDay);
}
}
The error suggests you are calling IsBetween like:
bool b = now.IsBetween();
but you need to provide the start and end times:
bool b = now.IsBetween(startTime, endTime);
is it possible to have something that can compare two dates in this format..
example today "Sep 30, 2013" and one week ago "Sep 22, 2013"
if its within this range say "good" if older then say "not good"
how can I make this in C# or vb.net
If difference between dates is smaller than 7 days, it will print "good" otherwise "Not good"
var ok = (firstDate-secondDate).TotalDays < 7? "good": "Not good";
Console.WriteLine(ok);
TotalDays is double so you can check if differnce is in full days, use Days if you want completed days difference as int
Read more about TimeSpan and it's properties.
if(date1 >= Convert.ToDateTime("Sep 22, 2013") && date1 <= Convert.ToDateTime("Sep 30, 2013"))
{
good
}
else
{
bad
}
You can use this generic Range class for checking some comparable value (like DateTime) falls into range:
public class Range<T>
where T : IComparable
{
public Range(T from, T to)
{
if (from.CompareTo(to) > 0)
throw new ArgumentException("From should not be greater than To");
From = from;
To = to;
}
public T From { get; private set; }
public T To { get; private set; }
public bool Contains(T value)
{
return value.CompareTo(From) >= 0 && value.CompareTo(To) <= 0;
}
// other methods like Intersects etc
}
Usage:
var today = DateTime.Today;
var range = new Range<DateTime>(today.AddDays(-7), today);
DateTime date = new DateTime(2013, 9, 25);
if (range.Contains(date))
// say good
thanks to all users who helped me here.. this is the final code that I am using..
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim fileDate As Date = Convert.ToDateTime("Sep 25, 2013")
Dim rightNow As Date = Convert.ToDateTime(Date.Now.ToString("MMM dd, yyyy"))
Dim lastWeek = rightNow.AddDays(-7)
If rightNow >= fileDate And lastWeek <= fileDate Then
Debug.Print("its new")
Else
Debug.Print("too old")
End If
End Sub
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());