Função para determinar primeiro dia de um mês, último dia de um mês, etc.
Pergunta
Estou criando um programador e necessidade de ser capaz de fazer o seguinte em C #:
- Encontre o terça-feira 1 de junho de 2012
- Encontre última sexta-feira Março de 2008
- Encontre todos os sábados em janeiro de 2013
- Encontre a 3ª sexta-feira em julho de 2009
- Encontre todos os sábados ao longo dos próximos 3 meses
- Encontre todos os dias março 2018
Os resultados devem voltar como DateTime
ou List<DateTime>
.
Solução
Aqui estão os métodos para encontrar o primeiro último dia / especificado de semana em um determinado mês:
public DateTime GetFirstDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
DateTime dt = new DateTime(year, month, 1);
int first = (int)dt.DayOfWeek;
int wanted = (int)dayOfWeek;
if (wanted < first)
wanted += 7;
return dt.AddDays(wanted - first);
}
public DateTime GetLastDayOfWeekInMonth(int year, int month, DayOfWeek dayOfWeek)
{
int daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth(year, month);
DateTime dt = new DateTime(year, month, daysInMonth);
int last = (int)dt.DayOfWeek;
int wanted = (int)dayOfWeek;
if (wanted > last)
last += 7;
return dt.AddDays(wanted - last);
}
A partir desses, você pode facilmente encontrar as respostas para as outras perguntas ... basta adicionar 7 dias para encontrar a próxima ocorrência do dia que você está procurando
EDIT: pensar mais sobre isso, seria muito útil para ter que sob a forma de métodos de extensão, tais como:
Console.WriteLine("Next monday : {0}", DateTime.Today.Next(DayOfWeek.Monday));
Console.WriteLine("Last saturday : {0}", DateTime.Today.Previous(DayOfWeek.Saturday));
Aqui está a implementação:
public static class DateExtensions
{
public static DateTime Next(this DateTime from, DayOfWeek dayOfWeek)
{
int start = (int)from.DayOfWeek;
int wanted = (int)dayOfWeek;
if (wanted < start)
wanted += 7;
return from.AddDays(wanted - start);
}
public static DateTime Previous(this DateTime from, DayOfWeek dayOfWeek)
{
int end = (int)from.DayOfWeek;
int wanted = (int)dayOfWeek;
if (wanted > end)
end += 7;
return from.AddDays(wanted - end);
}
}
É provavelmente mais flexíveis do que os primeiros métodos que eu sugeri ... Com isso, você pode facilmente fazer as coisas assim:
// Print all Sundays between 2009/01/01 and 2009/03/31
DateTime from = new DateTime(2009, 1, 1);
DateTime to = new DateTime(2009, 3, 31);
DateTime sunday = from.Next(DayOfWeek.Sunday);
while(sunday <= to)
{
Console.WriteLine(sunday);
sunday = sunday.AddDays(7);
}
Outras dicas
Inspirado por esta pergunta pareceu uma coisa divertida para fazer algo que lhe permite datas tratar como seqüências e consulta-los com LINQ. Eu fiz um projeto simples que pode ser baixado aqui do GitHub. Não sei se era necessário adicioná-lo ao controle de origem como eu duvido que vou estar trabalhando nisso, mas teve que carregá-lo em algum lugar e enviá-lo para RapidShare parecia um pouco duvidoso:)
As suas primeiras perguntas resolvido com a minha "Linq-to-DateTime":
/*
* 1. Find the 1st Tuesday of June 2012
2. Find the last Friday of March 2008
3. Find every Saturday in January 2013
4. Find the 3rd Friday in July 2009
5. Find every Saturday over the next 3 months
6. Find every day in March 2018
*/
var firstTuesday = (from d in DateSequence.FromYear(2012).June()
where d.DayOfWeek == DayOfWeek.Tuesday
select d).First();
var lastFriday = (from d in DateSequence.FromYear(2008).March()
where d.DayOfWeek == DayOfWeek.Friday
select d).Last();
var saturdays = (from d in DateSequence.FromYear(2013).January()
where d.DayOfWeek == DayOfWeek.Saturday
select d);
var thirdFriday = (from d in DateSequence.FromYear(2009).July()
where d.DayOfWeek == DayOfWeek.Friday
select d).Skip(2).First();
var nextSaturdays = (from d in DateSequence.FromDates(DateTime.Today, DateTime.Today.AddMonths(3))
where d.DayOfWeek == DayOfWeek.Saturday
select d);
var allDays = (from d in DateSequence.FromYear(2018).March()
select d);
Não é mostrado neste exemplo é que você pode escolher a granularidade de suas consultas. O que significa que se você fizer isso:
var days = (from d in DateSequence.FromYears(2001, 2090).AsYears()
where d.Year % 2 == 0
select d.Year).ToList();
Você vai percorrer os encontros com um incremento de um ano. O padrão é AsDays () se você não especificar nada.
O projeto é bastante barebone, há testes comentário ou unidade, mas espero que isso ainda pode ajudá-lo. Se não, então foi divertido escrever de qualquer maneira:)
Aqui está um exemplo de como fazer o primeiro dia de um mês.
public enum Month
{
January = 1,
Febuary = 2,
March = 3,
April = 4,
May = 5,
June = 6,
July = 7,
August = 8,
September = 9,
October = 10,
November = 11,
December = 12
}
public static Nullable<DateTime> FindTheFirstDayOfAMonth(DayOfWeek dayOfWeek, Month month, int year)
{
// Do checking of parameters here, i.e. year being in future not past
// Create a DateTime object the first day of that month
DateTime currentDate = new DateTime(year, (int)month, 1);
while (currentDate.Month == (int)month)
{
if (currentDate.DayOfWeek == dayOfWeek)
{
return currentDate;
}
currentDate = currentDate.AddDays(1);
}
return null;
}
Você chamá-lo como
Nullable<DateTime> date = Program.FindTheFirstDayOfAMonth(DayOfWeek.Monday, Month.September, 2009);
Assim que você começa a idéia. Você terá que fazer várias funções se o que você deseja alcançar.
YO YO YO - Vocês estão fazendo isso muito difícil:
= int DaysInMonth DateTime.DaysInMonth (DateTime.Now.Year, DateTime.Now.Month);
Quando eu escrevi um programador eu praticamente servidores SQL copiados sysschedules tabela
http://msdn.microsoft.com/en-us/library /ms178644.aspx
Usando coisas como Tipo Frequência, Frequência Intervalo, etc ... realmente tornou fácil para calcular os valores no código, mas eu estou supondo que há um sproc para fazer isso por você. Estou à procura de que agora.
Sim, o .NET Framework
apoiará que sem problemas;)
Mas a sério - você deve ser capaz de escrever código que faz isso com bastante facilidade. Se não, faça uma pergunta quando você ficar preso, e nós vamos ajudar. Mas você não precisa de nenhum montagens externas - basta ir com uma classe padrão C # =)