Jak znaleźć początek tygodnia (zarówno w niedzielę, jak i poniedziałek), znając tylko aktualny czas w C #?
Coś jak:
DateTime.Now.StartWeek(Monday);
Jak znaleźć początek tygodnia (zarówno w niedzielę, jak i poniedziałek), znając tylko aktualny czas w C #?
Coś jak:
DateTime.Now.StartWeek(Monday);
Odpowiedzi:
Użyj metody rozszerzenia. Są odpowiedzią na wszystko, wiesz! ;)
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
}
Które mogą być używane w następujący sposób:
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Sunday);
dt
jest UTC i jest już początek tygodnia, np 2012-09-02 16:00:00Z
który jest Mon, 03 Sep 2012 00:00:00
w czasie lokalnym. Więc musi przeliczyć dt
na czas lokalny lub zrobić coś mądrzejszego. Musi również zwrócić wynik jako UTC, jeśli dane wejściowe to UTC.
DateTime.Parse("2012-09-02 16:00:00Z")
zwraca ekwiwalent czasu lokalnego, a ta metoda poprawnie zwraca ten sam czas, co czas lokalny. Jeśli użyjesz DateTime.Parse("2012-09-02 16:00:00Z").ToUniversalTime()
do jawnego przekroczenia czasu UTC, ta metoda poprawnie zwróci 6 dni, 16 godzin wcześniej, jako czas UTC. Działa dokładnie tak, jak się spodziewałam.
dt
. Użyłemint diff = dt.Date.DayOfWeek - startOfWeek;
Najszybszym sposobem na wymyślenie tego jest:
var sunday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
Jeśli chcesz, aby jakikolwiek inny dzień tygodnia był Twoją datą początkową, wystarczy dodać wartość DayOfWeek na końcu
var monday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Monday);
var tuesday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Tuesday);
Trochę bardziej szczegółowy i świadomy kultury:
System.Globalization.CultureInfo ci =
System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
DayOfWeek today = DateTime.Now.DayOfWeek;
DateTime sow = DateTime.Now.AddDays(-(today - fdow)).Date;
CultureInfo.CurrentCulture
zamiast ściągać ją z wątku w ten sposób. Wydaje się to dziwnym sposobem na dostęp do niego.
Now
dwukrotne wywołanie nieruchomości. Jeśli aktualny czas upłynie 24:00 (lub 12:00 północy) między dwoma połączeniami, data ulegnie zmianie.
Korzystając z płynnego DateTime :
var monday = DateTime.Now.Previous(DayOfWeek.Monday);
var sunday = DateTime.Now.Previous(DayOfWeek.Sunday);
public static DateTime Previous(this DateTime start, DayOfWeek day) { do { start = start.PreviousDay(); } while (start.DayOfWeek != day); return start; }
Brzydkie, ale przynajmniej daje właściwe daty
Z początkiem tygodnia ustawionym przez system:
public static DateTime FirstDateInWeek(this DateTime dt)
{
while (dt.DayOfWeek != System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
dt = dt.AddDays(-1);
return dt;
}
Bez:
public static DateTime FirstDateInWeek(this DateTime dt, DayOfWeek weekStartDay)
{
while (dt.DayOfWeek != weekStartDay)
dt = dt.AddDays(-1);
return dt;
}
Połączmy odpowiedź bezpieczną dla kultury i odpowiedź metodą rozszerzenia:
public static class DateTimeExtensions
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
return DateTime.Today.AddDays(-(DateTime.Today.DayOfWeek- fdow));
}
}
dt
zamiast DateTime.Today
, aby zawinąć matematykę w (offset + 7) % 7
celu zapewnienia ujemnego przesunięcia, aby użyć przeciążenia metody jednoparametrowej, która przekazuje argumenty bieżącej kultury FirstDayOfWeek
jako startOfWeek
argument, i ewentualnie (w zależności od specyfikacji) wymusić zero przesunięcia do 7-dniowego przesunięcia, aby „ostatni wtorek” nie powrócił dzisiaj, jeśli jest już wtorek.
Może to być trochę włamanie, ale możesz rzucić właściwość .DayOfWeek na int (jest to wyliczenie, a ponieważ nie zmieniono podstawowego typu danych, domyślnie jest to int) i użyć tego, aby określić poprzedni początek tygodnia .
Wydaje się, że tydzień określony w wyliczeniu DayOfWeek rozpoczyna się w niedzielę, więc jeśli odejmiemy 1 od tej wartości, będzie to równa liczbie dni, w które poniedziałek przypada przed bieżącą datą. Musimy również zmapować niedzielę (0) na wartość równą 7, więc biorąc pod uwagę 1 - 7 = -6 niedziela zmapuje do poprzedniego poniedziałku: -
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
dayOfWeek = dayOfWeek == 0 ? 7 : dayOfWeek;
DateTime startOfWeek = now.AddDays(1 - (int)now.DayOfWeek);
Kod z poprzedniej niedzieli jest prostszy, ponieważ nie musimy dokonywać tej korekty: -
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
DateTime startOfWeek = now.AddDays(-(int)now.DayOfWeek);
Na poniedziałek
DateTime startAtMonday = DateTime.Now.AddDays(DayOfWeek.Monday - DateTime.Now.DayOfWeek);
Na niedzielę
DateTime startAtSunday = DateTime.Now.AddDays(DayOfWeek.Sunday- DateTime.Now.DayOfWeek);
using System;
using System.Globalization;
namespace MySpace
{
public static class DateTimeExtention
{
// ToDo: Need to provide culturaly neutral versions.
public static DateTime GetStartOfWeek(this DateTime dt)
{
DateTime ndt = dt.Subtract(TimeSpan.FromDays((int)dt.DayOfWeek));
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfWeek(this DateTime dt)
{
DateTime ndt = dt.GetStartOfWeek().AddDays(6);
return new DateTime(ndt.Year, ndt.Month, ndt.Day, 23, 59, 59, 999);
}
public static DateTime GetStartOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetStartOfWeek();
}
public static DateTime GetEndOfWeek(this DateTime dt, int year, int week)
{
DateTime dayInWeek = new DateTime(year, 1, 1).AddDays((week - 1) * 7);
return dayInWeek.GetEndOfWeek();
}
}
}
Łącząc to wszystko z Globalizacją i pozwalając określić pierwszy dzień tygodnia w ramach naszego zaproszenia
public static DateTime StartOfWeek ( this DateTime dt, DayOfWeek? firstDayOfWeek )
{
DayOfWeek fdow;
if ( firstDayOfWeek.HasValue )
{
fdow = firstDayOfWeek.Value;
}
else
{
System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
fdow = ci.DateTimeFormat.FirstDayOfWeek;
}
int diff = dt.DayOfWeek - fdow;
if ( diff < 0 )
{
diff += 7;
}
return dt.AddDays( -1 * diff ).Date;
}
var now = System.DateTime.Now;
var result = now.AddDays(-((now.DayOfWeek - System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 7) % 7)).Date;
To da ci północ w pierwszą niedzielę tygodnia:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, t.Hour, t.Minute, t.Second);
To daje pierwszy poniedziałek o północy:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek - 1, t.Hour, t.Minute, t.Second);
spróbuj tego w c #. Za pomocą tego kodu możesz uzyskać zarówno pierwszą datę, jak i ostatnią datę danego tygodnia. Tutaj niedziela jest pierwszym dniem, a sobota jest ostatnim dniem, ale możesz ustawić oba dni zgodnie z własną kulturą
DateTime firstDate = GetFirstDateOfWeek(DateTime.Parse("05/09/2012").Date,DayOfWeek.Sunday);
DateTime lastDate = GetLastDateOfWeek(DateTime.Parse("05/09/2012").Date, DayOfWeek.Saturday);
public static DateTime GetFirstDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime firstDayInWeek = dayInWeek.Date;
while (firstDayInWeek.DayOfWeek != firstDay)
firstDayInWeek = firstDayInWeek.AddDays(-1);
return firstDayInWeek;
}
public static DateTime GetLastDateOfWeek(DateTime dayInWeek, DayOfWeek firstDay)
{
DateTime lastDayInWeek = dayInWeek.Date;
while (lastDayInWeek.DayOfWeek != firstDay)
lastDayInWeek = lastDayInWeek.AddDays(1);
return lastDayInWeek;
}
Próbowałem kilka, ale nie rozwiązałem problemu z tygodniem rozpoczynającym się w poniedziałek, co dało mi przyszły poniedziałek w niedzielę. Więc trochę go zmodyfikowałem i działałem z tym kodem:
int delta = DayOfWeek.Monday - DateTime.Now.DayOfWeek;
DateTime monday = DateTime.Now.AddDays(delta == 1 ? -6 : delta);
return monday;
dt.AddDays(DayOfWeek.Monday - dt.DayOfWeek);
Krok 1: Utwórz klasę statyczną
public static class TIMEE
{
public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 + (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(-1 * diff).Date;
}
public static DateTime EndOfWeek(this DateTime dt, DayOfWeek startOfWeek)
{
int diff = (7 - (dt.DayOfWeek - startOfWeek)) % 7;
return dt.AddDays(1 * diff).Date;
}
}
Krok 2: Użyj tej klasy, aby uzyskać początek i koniec dnia tygodnia
DateTime dt =TIMEE.StartOfWeek(DateTime.Now ,DayOfWeek.Monday);
DateTime dt1 = TIMEE.EndOfWeek(DateTime.Now, DayOfWeek.Sunday);
(6 - (dt.DayOfWeek - startOfWeek)) % 7
w stosunku do testów jednostkowych, które napisałem.
Następująca metoda powinna zwrócić wybraną datę i godzinę. Przekaż prawdę, ponieważ niedziela jest pierwszym dniem tygodnia, fałsz w poniedziałek:
private DateTime getStartOfWeek(bool useSunday)
{
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
if(!useSunday)
dayOfWeek--;
if(dayOfWeek < 0)
{// day of week is Sunday and we want to use Monday as the start of the week
// Sunday is now the seventh day of the week
dayOfWeek = 6;
}
return now.AddDays(-1 * (double)dayOfWeek);
}
Dzięki za przykłady. Musiałem zawsze używać „CurrentCulture” pierwszego dnia tygodnia, a dla tablicy musiałem znać dokładną liczbę dni… więc oto moje pierwsze rozszerzenia:
public static class DateTimeExtensions
{
//http://stackoverflow.com/questions/38039/how-can-i-get-the-datetime-for-the-start-of-the-week
//http://stackoverflow.com/questions/1788508/calculate-date-with-monday-as-dayofweek1
public static DateTime StartOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return dt.AddDays(-1 * diff).Date;
}
public static int DayNoOfWeek(this DateTime dt)
{
//difference in days
int diff = (int)dt.DayOfWeek - (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek; //sunday=always0, monday=always1, etc.
//As a result we need to have day 0,1,2,3,4,5,6
if (diff < 0)
{
diff += 7;
}
return diff + 1; //Make it 1..7
}
}
Wydaje się, że nikt jeszcze nie odpowiedział na to poprawnie. Wkleję tutaj moje rozwiązanie na wypadek, gdyby ktoś go potrzebował. Poniższy kod działa niezależnie od tego, czy pierwszy dzień tygodnia to poniedziałek, niedziela czy coś innego.
public static class DateTimeExtension
{
public static DateTime GetFirstDayOfThisWeek(this DateTime d)
{
CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
var first = (int)ci.DateTimeFormat.FirstDayOfWeek;
var current = (int)d.DayOfWeek;
var result = first <= current ?
d.AddDays(-1 * (current - first)) :
d.AddDays(first - current - 7);
return result;
}
}
class Program
{
static void Main()
{
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine("Current culture set to en-US");
RunTests();
Console.WriteLine();
System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("da-DK");
Console.WriteLine("Current culture set to da-DK");
RunTests();
Console.ReadLine();
}
static void RunTests()
{
Console.WriteLine("Today {1}: {0}", DateTime.Today.Date.GetFirstDayOfThisWeek(), DateTime.Today.Date.ToString("yyyy-MM-dd"));
Console.WriteLine("Saturday 2013-03-02: {0}", new DateTime(2013, 3, 2).GetFirstDayOfThisWeek());
Console.WriteLine("Sunday 2013-03-03: {0}", new DateTime(2013, 3, 3).GetFirstDayOfThisWeek());
Console.WriteLine("Monday 2013-03-04: {0}", new DateTime(2013, 3, 4).GetFirstDayOfThisWeek());
}
}
Modulo w C # działa źle dla -1mod7 (powinno być 6, c # zwraca -1), więc ... "oneliner" rozwiązanie tego będzie wyglądać tak :)
private static DateTime GetFirstDayOfWeek(DateTime date)
{
return date.AddDays(-(((int)date.DayOfWeek - 1) - (int)Math.Floor((double)((int)date.DayOfWeek - 1) / 7) * 7));
}
To samo na koniec tygodnia (w stylu @Compile To jest odpowiedź):
public static DateTime EndOfWeek(this DateTime dt)
{
int diff = 7 - (int)dt.DayOfWeek;
diff = diff == 7 ? 0 : diff;
DateTime eow = dt.AddDays(diff).Date;
return new DateTime(eow.Year, eow.Month, eow.Day, 23, 59, 59, 999) { };
}
Możesz użyć doskonałej biblioteki Umbrella :
using nVentive.Umbrella.Extensions.Calendar;
DateTime beginning = DateTime.Now.BeginningOfWeek();
Jednak oni nie wydają się być przechowywane w poniedziałek jako pierwszy dzień tygodnia (patrz właściwośćnVentive.Umbrella.Extensions.Calendar.DefaultDateTimeCalendarExtensions.WeekBeginsOn
), tak, że poprzednie rozwiązanie zlokalizowana jest nieco lepiej. Niefortunny.
Edycja : patrząc bliżej na pytanie, wygląda na to, że Parasol też może na to zadziałać:
// Or DateTime.Now.PreviousDay(DayOfWeek.Monday)
DateTime monday = DateTime.Now.PreviousMonday();
DateTime sunday = DateTime.Now.PreviousSunday();
Chociaż warto zauważyć, że jeśli poprosisz o poprzedni poniedziałek w poniedziałek, da ci to siedem dni wstecz. Ale jest to również prawdą, jeśli używasz BeginningOfWeek
, co wydaje się błędem :(.
Zwróci zarówno początek tygodnia, jak i koniec tygodnia:
private string[] GetWeekRange(DateTime dateToCheck)
{
string[] result = new string[2];
TimeSpan duration = new TimeSpan(0, 0, 0, 0); //One day
DateTime dateRangeBegin = dateToCheck;
DateTime dateRangeEnd = DateTime.Today.Add(duration);
dateRangeBegin = dateToCheck.AddDays(-(int)dateToCheck.DayOfWeek);
dateRangeEnd = dateToCheck.AddDays(6 - (int)dateToCheck.DayOfWeek);
result[0] = dateRangeBegin.Date.ToString();
result[1] = dateRangeEnd.Date.ToString();
return result;
}
Na moim blogu ZamirsBlog zamieściłem pełny kod do obliczania początku / końca tygodnia, miesiąca, kwartału i roku
namespace DateTimeExample
{
using System;
public static class DateTimeExtension
{
public static DateTime GetMonday(this DateTime time)
{
if (time.DayOfWeek != DayOfWeek.Monday)
return GetMonday(time.AddDays(-1)); //Recursive call
return time;
}
}
internal class Program
{
private static void Main()
{
Console.WriteLine(DateTime.Now.GetMonday());
Console.ReadLine();
}
}
}
Oto kombinacja kilku odpowiedzi. Wykorzystuje metodę rozszerzenia, która umożliwia przekazanie kultury, jeśli nie zostanie przekazana, używana jest bieżąca kultura. Zapewni to maksymalną elastyczność i ponowne użycie.
/// <summary>
/// Gets the date of the first day of the week for the date.
/// </summary>
/// <param name="date">The date to be used</param>
/// <param name="cultureInfo">If none is provided, the current culture is used</param>
/// <returns>The date of the beggining of the week based on the culture specifed</returns>
public static DateTime StartOfWeek(this DateTime date, CultureInfo cultureInfo=null) =>
date.AddDays(-1 * (7 + (date.DayOfWeek - (cultureInfo??CultureInfo.CurrentCulture).DateTimeFormat.FirstDayOfWeek)) % 7).Date;
Przykładowe użycie:
public static void TestFirstDayOfWeekExtension() {
DateTime date = DateTime.Now;
foreach(System.Globalization.CultureInfo culture in CultureInfo.GetCultures(CultureTypes.UserCustomCulture | CultureTypes.SpecificCultures)) {
Console.WriteLine($"{culture.EnglishName}: {date.ToShortDateString()} First Day of week: {date.StartOfWeek(culture).ToShortDateString()}");
}
}
jeśli chcesz w sobotę lub niedzielę lub w dowolny dzień tygodnia, ale nie dłużej niż w bieżącym tygodniu (sob. – niedz.), obdarzyłem cię tym kodem.
public static DateTime GetDateInCurrentWeek(this DateTime date, DayOfWeek day)
{
var temp = date;
var limit = (int)date.DayOfWeek;
var returnDate = DateTime.MinValue;
if (date.DayOfWeek == day) return date;
for (int i = limit; i < 6; i++)
{
temp = temp.AddDays(1);
if (day == temp.DayOfWeek)
{
returnDate = temp;
break;
}
}
if (returnDate == DateTime.MinValue)
{
for (int i = limit; i > -1; i++)
{
date = date.AddDays(-1);
if (day == date.DayOfWeek)
{
returnDate = date;
break;
}
}
}
return returnDate;
}
Kontynuując kompilowanie tej odpowiedzi, użyj następującej metody, aby uzyskać datę dla dowolnego dnia tygodnia:
public static DateTime GetDayOfWeek(this DateTime dt, DayOfWeek day)
{
int diff = (7 + (dt.DayOfWeek - DayOfWeek.Monday)) % 7;
var monday = dt.AddDays(-1 * diff).Date;
switch (day)
{
case DayOfWeek.Tuesday:
return monday.AddDays(1).Date;
case DayOfWeek.Wednesday:
return monday.AddDays(2).Date;
case DayOfWeek.Thursday:
return monday.AddDays(3).Date;
case DayOfWeek.Friday:
return monday.AddDays(4).Date;
case DayOfWeek.Saturday:
return monday.AddDays(5).Date;
case DayOfWeek.Sunday:
return monday.AddDays(6).Date;
}
return monday;
}
Spróbuj utworzyć funkcję korzystającą z rekurencji. Twój obiekt DateTime jest wejściem, a funkcja zwraca nowy obiekt DateTime, który oznacza początek tygodnia.
DateTime WeekBeginning(DateTime input)
{
do
{
if (input.DayOfWeek.ToString() == "Monday")
return input;
else
return WeekBeginning(input.AddDays(-1));
} while (input.DayOfWeek.ToString() == "Monday");
}
Obliczenie w ten sposób pozwala wybrać, który dzień tygodnia wskazuje początek nowego tygodnia (w przykładzie, który wybrałem w poniedziałek).
Pamiętaj, że wykonanie tego obliczenia dla dnia, który jest w poniedziałek, da bieżący poniedziałek, a nie poprzedni.
//Replace with whatever input date you want
DateTime inputDate = DateTime.Now;
//For this example, weeks start on Monday
int startOfWeek = (int)DayOfWeek.Monday;
//Calculate the number of days it has been since the start of the week
int daysSinceStartOfWeek = ((int)inputDate.DayOfWeek + 7 - startOfWeek) % 7;
DateTime previousStartOfWeek = inputDate.AddDays(-daysSinceStartOfWeek);
int diff = dayOfWeek - dt.DayOfWeek; return dt.AddDays(diff).Date;