¿Cómo encuentro el comienzo de la semana (tanto el domingo como el lunes) sabiendo solo la hora actual en C #?
Algo como:
DateTime.Now.StartWeek(Monday);
¿Cómo encuentro el comienzo de la semana (tanto el domingo como el lunes) sabiendo solo la hora actual en C #?
Algo como:
DateTime.Now.StartWeek(Monday);
Respuestas:
Utiliza un método de extensión. Son la respuesta a todo, ¿sabes? ;)
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;
}
}
Que se puede usar de la siguiente manera:
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime dt = DateTime.Now.StartOfWeek(DayOfWeek.Sunday);
dt
es UTC y ya es el comienzo de la semana, por ejemplo, 2012-09-02 16:00:00Z
que es Mon, 03 Sep 2012 00:00:00
en hora local. Por lo tanto, debe convertirse dt
a la hora local o hacer algo un poco más inteligente. También necesitaría devolver el resultado como UTC si la entrada fue UTC.
DateTime.Parse("2012-09-02 16:00:00Z")
devuelve el equivalente de hora local, y este método devuelve correctamente la misma hora que la hora local. Si usa DateTime.Parse("2012-09-02 16:00:00Z").ToUniversalTime()
para pasar explícitamente la hora UTC, este método devuelve correctamente 6 días, 16 horas antes, como hora UTC. Funciona exactamente como esperaba.
dt
. Yo solíaint diff = dt.Date.DayOfWeek - startOfWeek;
La forma más rápida que puedo encontrar es:
var sunday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
Si desea que cualquier otro día de la semana sea su fecha de inicio, todo lo que necesita hacer es agregar el valor de DayOfWeek al final
var monday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Monday);
var tuesday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + (int)DayOfWeek.Tuesday);
Un poco más detallado y culturalmente consciente:
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
lugar de sacarlo del hilo de esa manera. Parece una forma extraña de acceder.
Now
propiedad dos veces. Si la hora actual pasa las 24:00 (o las 12:00 de la medianoche) entre las dos llamadas, la fecha habrá cambiado.
Usando Fluent 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; }
Feo pero al menos devuelve las fechas correctas
Con inicio de semana establecido por sistema:
public static DateTime FirstDateInWeek(this DateTime dt)
{
while (dt.DayOfWeek != System.Threading.Thread.CurrentThread.CurrentCulture.DateTimeFormat.FirstDayOfWeek)
dt = dt.AddDays(-1);
return dt;
}
Sin:
public static DateTime FirstDateInWeek(this DateTime dt, DayOfWeek weekStartDay)
{
while (dt.DayOfWeek != weekStartDay)
dt = dt.AddDays(-1);
return dt;
}
Combinemos la respuesta segura para la cultura y la respuesta del método de extensión:
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
lugar de DateTime.Today
, para envolver las matemáticas en un (offset + 7) % 7
para asegurar un desplazamiento negativo, para usar una sobrecarga del método de un solo parámetro que pasa la cultura actual FirstDayOfWeek
como startOfWeek
argumento, y posiblemente (dependiendo de la especificación) para forzar un compensación de cero a una compensación de 7 días, de modo que "el martes pasado" no regrese hoy si ya es martes.
Esto puede ser un poco pirateo, pero puede convertir la propiedad .DayOfWeek a un int (es una enumeración y, dado que no ha cambiado su tipo de datos subyacente, el valor predeterminado es int) y usarlo para determinar el comienzo de la semana anterior .
Parece que la semana especificada en la enumeración DayOfWeek comienza el domingo, por lo que si restamos 1 de este valor, será igual a cuántos días es el lunes antes de la fecha actual. También necesitamos mapear el domingo (0) para igualar 7, por lo tanto, dado 1 - 7 = -6, el domingo se mapeará al lunes anterior: -
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
dayOfWeek = dayOfWeek == 0 ? 7 : dayOfWeek;
DateTime startOfWeek = now.AddDays(1 - (int)now.DayOfWeek);
El código del domingo anterior es más simple ya que no tenemos que hacer este ajuste: -
DateTime now = DateTime.Now;
int dayOfWeek = (int)now.DayOfWeek;
DateTime startOfWeek = now.AddDays(-(int)now.DayOfWeek);
Para el lunes
DateTime startAtMonday = DateTime.Now.AddDays(DayOfWeek.Monday - DateTime.Now.DayOfWeek);
Para el domingo
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();
}
}
}
Poniendo todo junto, con Globalización y permitiendo especificar el primer día de la semana como parte de la llamada que tenemos
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;
Esto te daría medianoche el primer domingo de la semana:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek, t.Hour, t.Minute, t.Second);
Esto te da el primer lunes a medianoche:
DateTime t = DateTime.Now;
t -= new TimeSpan ((int) t.DayOfWeek - 1, t.Hour, t.Minute, t.Second);
intente con esto en c #. Con este código puede obtener la primera fecha y la última fecha de una semana determinada. Aquí el domingo es el primer día y el sábado es el último día, pero puede configurar ambos días de acuerdo con su cultura
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;
}
Intenté varios, pero no resolví el problema con una semana que comenzó un lunes, lo que me dio el próximo lunes un domingo. Así que lo modifiqué un poco y lo hice funcionar con este código:
int delta = DayOfWeek.Monday - DateTime.Now.DayOfWeek;
DateTime monday = DateTime.Now.AddDays(delta == 1 ? -6 : delta);
return monday;
dt.AddDays(DayOfWeek.Monday - dt.DayOfWeek);
Paso 1: crea una clase estática
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;
}
}
Paso 2: use esta clase para obtener el día de inicio y finalización de la semana
DateTime dt =TIMEE.StartOfWeek(DateTime.Now ,DayOfWeek.Monday);
DateTime dt1 = TIMEE.EndOfWeek(DateTime.Now, DayOfWeek.Sunday);
(6 - (dt.DayOfWeek - startOfWeek)) % 7
para mí contra las pruebas unitarias que escribí.
El siguiente método debería devolver el DateTime que desea. Pase verdadero para el domingo siendo el primer día de la semana, falso para el lunes:
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);
}
Gracias por los ejemplos. Siempre necesitaba usar el "CurrentCulture" el primer día de la semana y para una matriz necesitaba saber el número de día exacto ... así que aquí están mis primeras extensiones:
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
}
}
Nadie parece haber respondido esto correctamente todavía. Pegaré mi solución aquí en caso de que alguien la necesite. El siguiente código funciona independientemente de si el primer día de la semana es un lunes o un domingo u otra cosa.
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());
}
}
El módulo en C # funciona mal para -1mod7 (debería ser 6, c # devuelve -1) así que ... la solución "oneliner" se verá así :)
private static DateTime GetFirstDayOfWeek(DateTime date)
{
return date.AddDays(-(((int)date.DayOfWeek - 1) - (int)Math.Floor((double)((int)date.DayOfWeek - 1) / 7) * 7));
}
Lo mismo para el final de la semana (al estilo de @Compile).
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) { };
}
Podrías usar la excelente biblioteca Umbrella :
using nVentive.Umbrella.Extensions.Calendar;
DateTime beginning = DateTime.Now.BeginningOfWeek();
Sin embargo, no parecen haber almacenado el lunes como el primer día de la semana (ver la propiedad nVentive.Umbrella.Extensions.Calendar.DefaultDateTimeCalendarExtensions.WeekBeginsOn
), por lo que la solución localizada anterior es un poco mejor. Desgraciado.
Editar : mirando más de cerca la pregunta, parece que Umbrella podría funcionar para eso también:
// Or DateTime.Now.PreviousDay(DayOfWeek.Monday)
DateTime monday = DateTime.Now.PreviousMonday();
DateTime sunday = DateTime.Now.PreviousSunday();
Aunque vale la pena señalar que si solicita el lunes anterior un lunes, le devolverá siete días. Pero esto también es cierto si lo usa BeginningOfWeek
, lo que parece un error :(.
Esto devolverá las fechas de inicio y fin de semana:
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;
}
He publicado el código completo para calcular el inicio / fin de semana, mes, trimestre y año en mi blog ZamirsBlog
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();
}
}
}
Aquí hay una combinación de algunas de las respuestas. Utiliza un método de extensión que permite pasar la cultura, si no se pasa una, se usa la cultura actual. Esto le dará la máxima flexibilidad y reutilización.
/// <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;
Ejemplo de uso:
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()}");
}
}
si quiere el sábado o el domingo o cualquier día de la semana pero que no exceda la semana actual (sábado a domingo), lo cubro con este código.
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;
}
Nos gustan las frases sencillas: obtenga la diferencia entre el primer día de la semana de la cultura actual y el día actual, luego reste la cantidad de días del día actual
var weekStartDate = DateTime.Now.AddDays(-((int)now.DayOfWeek - (int)DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek));
Siguiendo de Compile This 'Answer, use el siguiente método para obtener la fecha de cualquier día de la semana:
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;
}
Intenta crear una función que utilice la recursividad. Su objeto DateTime es una entrada y la función devuelve un nuevo objeto DateTime que representa el comienzo de la semana.
DateTime WeekBeginning(DateTime input)
{
do
{
if (input.DayOfWeek.ToString() == "Monday")
return input;
else
return WeekBeginning(input.AddDays(-1));
} while (input.DayOfWeek.ToString() == "Monday");
}
Calcular de esta manera le permite elegir qué día de la semana indica el comienzo de una nueva semana (en el ejemplo que elegí el lunes).
Tenga en cuenta que hacer este cálculo para un día que es lunes dará el lunes actual y no el anterior.
//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;