Get next Hannukah date in C# - c#

I am trying to find out from today's UTC date the date of the next Hannukah.
I already found that C# has HebrewCalendar class and I was able to get the current Jewish date with GetYear(), GetMonth()andGetDayOfMonth(). But don't really know how to work with this information to get the Jewish date that is gonna happen next for the current date.
Hannukah is dated on 25th of Kislev (3rd month in Jewish calendar).

#DmitryBychenko's answer is fine, although if you don't want to loop, you can also calculate it:
var calendar = new HebrewCalendar();
var result = DateTime.UtcNow;
if(
calendar.GetMonth(result) < 3
|| (calendar.GetMonth(result)==3 && calendar.GetDayOfMonth(result)<25)
)
result = new DateTime(calendar.GetYear(result), 3, 25, calendar);
else
result = new DateTime(calendar.GetYear(result)+1, 3, 25, calendar);
If you are under 25/3 on the HebrewCalendar, use this year, else use next
Result is also 7 Dec 2015 in the gregorian calendar
If (as per the comments) you don't want those pesky if statements for some reason, you could do something like:
var calendar = new HebrewCalendar();
var result = DateTime.UtcNow;
var addYear = (calendar.GetMonth(result) < 3 || (calendar.GetMonth(result)==3 && calendar.GetDayOfMonth(result)<25)) ? 0 : 1;
result = new DateTime(calendar.GetYear(result) + addYear, 3, 25, calendar);
I don't think this helps readability but there you go

As it was suggested on Twitter, here's a Noda Time solution:
// As of 2.0, it will be CalendarSystem.HebrewCivil
var calendar = CalendarSystem.GetHebrewCalendar(HebrewMonthNumbering.Civil);
var today = SystemClock.Instance.InZone(DateTimeZone.Utc, calendar).Date;
var thisHannukah = new LocalDate(today.Year, 3, 25, calendar);
return thisHannukah >= today ? thisHannukah : thisHannukah.PlusYears(1);
Alternative for the last two statements:
var year = today.Month < 3 || today.Month == 3 && today.Day <= 25
? today.Year : today.Year + 1;
return new LocalDate(year, 3, 25, calendar);
If we go ahead with feature request 317, this could be much simpler. For example:
// Putative API only! Doesn't work yet!
MonthDay hannukah = new MonthDay(3, 25, calendar);
var nextHannukah = hannukah.NextOrSame(today);

Eh, just looping? Testing date one by one starting from, say, DateTime.Now?
HebrewCalendar calendar = new HebrewCalendar();
DateTime result = DateTime.Now;
for (DateTime date = DateTime.Now.Date; ; date = date.AddDays(1)) {
if (calendar.GetDayOfMonth(date) == 25 && calendar.GetMonth(date) == 3) {
result = date;
break;
}
}
it returns result == 7 Dec 2015?

Related

How to select weekends with an interval between them?

How can I select all weekends until the end of the year, with some criteria to be followed?
User input desired Weekend day:
18/12/2021
Software must out:
25/12/2022 (must be ignored)
01/01/2022
08/01/2022 (must be ignored)
15/01/2022
22/01/2022 (must be ignored)
29/01/2022 and so on...
What i have now:
public void GetWeekends() {
var lastWorkedWeekend = dateTimePicker1.Value;
var workedInSunday = checkBox1.Checked;
var list = new List < DateTime > ();
var weekends = GetDaysBetween(lastWorkedWeekend, DateTime.Today.AddDays(365)).Where(d => d.DayOfWeek == DayOfWeek.Saturday);
var selected = true;
for (int i = 0; i < weekends.Count(); i++) {
if (selected == false) {
list.Add(weekends.ElementAt(i));
selected = true;
} else {
selected = false;
}
}
}
I think I'd just scroll the input day forward until it was saturday (or calculate it, but i find the loop more self documenting than casting DayOfWeek to an int and factoring for sunday being 0) then add 14 days repeatedly. This skips over the 25th, etc..
var d = new DateTime(2021, 12, 18);
while(d.DayOfWeek != DayOfWeek.Saturday)
d += TimeSpan.FromDays(1);
while(d.Year == 2021){ //was your 2022 a typo? or maybe make this <= 2022.. I'm not sure what you want there..
d += TimeSpan.FromDays(14);
Console.WriteLine(d);
}
You might prefer DateTime.AddDays()..
Looks to me that you want to get the date of every second weekend from an initial date until the end of the year. In your example, you kinda bleed over to the next year.
public static void Main()
{
var dates = GetDateTimeRange(new DateTime(2021, 12, 18), new DateTime(2023, 1, 1), TimeSpan.FromDays(14));
foreach (var dateTime in dates.Skip(1))
{
Console.WriteLine(dateTime);
}
}
public static IEnumerable<DateTime> GetDateTimeRange(DateTime startingDate, DateTime endDate, TimeSpan interval)
{
var lastDate = startingDate;
while (lastDate < endDate)
{
yield return lastDate;
lastDate = lastDate.Add(interval);
}
}
This returns
01/01/2022 00:00:00
01/15/2022 00:00:00
01/29/2022 00:00:00
02/12/2022 00:00:00
02/26/2022 00:00:00
03/12/2022 00:00:00
03/26/2022 00:00:00
04/09/2022 00:00:00
04/23/2022 00:00:00
05/07/2022 00:00:00
05/21/2022 00:00:00
06/04/2022 00:00:00
06/18/2022 00:00:00
07/02/2022 00:00:00
07/16/2022 00:00:00
07/30/2022 00:00:00
08/13/2022 00:00:00
08/27/2022 00:00:00
09/10/2022 00:00:00
09/24/2022 00:00:00
10/08/2022 00:00:00
10/22/2022 00:00:00
11/05/2022 00:00:00
11/19/2022 00:00:00
12/03/2022 00:00:00
12/17/2022 00:00:00
12/31/2022 00:00:00
One approach is to use a method that creates an enumerable of dates. Once that's done you can use LINQ queries. If creating that enumerable is expensive you could just create one large range encompassing years and re-use it.
Or you might find better performance by just creating the range you need for each query.
public static class DateRanges
{
public static IEnumerable<DateOnly> GetRange(DateOnly start, DateOnly end)
{
for (var date = start; date <= end; date = date.AddDays(1))
{
yield return date;
}
}
}
It's not clear from your code what the criteria is, but this does what you described - all weekends from now to the end of the year.
var today = DateOnly.FromDateTime(DateTime.Today);
var lastDayOfYear = DateOnly.FromDateTime(new DateTime(DateTime.Today.Year, 12, 31));
var dates = DateRanges.GetRange(today, lastDayOfYear);
var weekendsOnly = dates.Where(date =>
date.DayOfWeek == DayOfWeek.Saturday);
Or if you prefer to create one date range and query it repeatedly:
// Big range of dates, 10 years into past and future.
// Create this once and re-use it
var dates = DateRanges.GetRange(
DateOnly.FromDateTime(DateTime.Today.AddYears(-10)),
DateOnly.FromDateTime(DateTime.Today.AddYears(10)));
var today = DateOnly.FromDateTime(DateTime.Today);
var lastDayOfYear = DateOnly.FromDateTime(new DateTime(DateTime.Today.Year, 12, 31));
var weekendsOnly = dates.Where(date =>
date >= today
&& date <= lastDayOfYear
&& date.DayOfWeek == DayOfWeek.Saturday);
In either case if you want every other Saturday you can add
.Where((date, i) => i % 2 == 0);
Or to maintain that readability you could put that in another extension like
public static IEnumerable<T> EveryOther<T>(this IEnumerable<T> source)
{
return source.Where((date, i) => i % 2 == 0);
}
so your query looks like
var everyOtherWeekend = dates
.Where(date =>
date >= today
&& date <= lastDayOfYear
&& date.DayOfWeek == DayOfWeek.Saturday)
.EveryOther();
I wouldn't position this as a better answer than those that iterate over a series of dates. The difference is that instead of having to write a method for any query you can start with a range of dates and then use LINQ to filter it. That makes it a little easier to read and to compose different queries.

Loop through current month to next month in c#

I am facing a problem, logic written in my program is below
DataSet dslsip = mAE_Repo.FetchLastDayCustEmailsEquity_SIP_Content();
var ressip = (from r in dslsip.Tables[0].AsEnumerable() select r.Field<string>("emailid")).ToList();
var resdate = (from r in dslsip.Tables[0].AsEnumerable() select r.Field<DateTime>("a_confirmdatetime")).ToList();
//var datetime = DateTime.Now;
//List<string> date = new List<string>();
//List<DateTime> date = new List<DateTime>();
if (!ReferenceEquals(resdate,null) && resdate.Count>0)
{
for (int i = 0; i < resdate.Count()-1; i++)
{
if (resdate[i].Month == DateTime.Now.Month || resdate[i].Month < DateTime.Now.Month)
{
//Logic should write here
//var das = DateTime.Now.AddMonths(1).ToString("MM");
//var datet = resdate[i].AddMonths(1).ToString("MM");
}
}
}
In the above code 'resdate' variable I'm fetching the list of the dates
And the concept is I should add the month (current next month) Ex: {05-07-2021 00:00:00} I should add the (current month is 9 and next month is 10) so it should be {05-10-2021 00:00:00}
I'm not sure how to add the month only.
I'm new to coding.
Please help me in this.
Use AddMonths() function, example:
new DateTime(DateTime.Now.AddMonths(1).Year,
DateTime.Now.AddMonths(1).Month,
d.Day);
Output:
10/5/2021 12:00:00 AM
10/1/2021 12:00:00 AM
You need to change Month from date list. So, you can do it by using AddMonths() API. Used below Sample :
if (resdate[i].Month == DateTime.Now.Month || resdate[i].Month < DateTime.Now.Month)
{
//Logic should write here
var datet = new DateTime(resdate[i].Year, DateTime.Now.AddMonths(1).Month, resdate[i].Day, resdate[i].Hour, resdate[i].Minute, resdate[i].Second);
}
Here we modified only month data As you wanted.

Getting last 7 days data from days name like sunday, monday, tuesday etc in linq asp.net mvc

I want to fetch data by last week days like last Sunday, last Monday and so on 7 days. I wrote this query but I returns null.
var dateCriteria = DateTime.Now.Date.AddDays(-7);
var one = _context.Sale.Where(m => m.Date >= dateCriteria && m.Date.DayOfWeek.ToString() ==
"Sunday");
DayOfWeek is enum. So just use it without conversion:
var dateCriteria = DateTime.Now.Date.AddDays(-7);
var one = _context.Sale.Where(m => m.Date >= dateCriteria && m.Date.DayOfWeek ==
DayOfWeek.Sunday);
I am not sure if I understood your question correctly but here is what I would do to get the last Sunday's sales.
var one = _context.Sale.Where(m => m.Date == GetLast(DayOfWeek.Sunday));
private DateTime GetLast(DayOfWeek dayOfWeek) {
var currentDate = DateTime.Now.Date;
var currentDayOfWeek = (int)currentDate.DayOfWeek;
if (currentDayOfWeek <= (int)dayOfWeek) {
currentDayOfWeek = currentDayOfWeek + 7;
}
int daysToExtract = currentDayOfWeek - (int)dayOfWeek;
return currentDate.AddDays(-daysToExtract);
}

How to get Range between TWO dates in Asp.Net..?

I have Two DatePicker in TextBox. I wants print all the dates between to range of textBox. How to insert those multiple dates in database...?
Example:
In First TextBox :- 1 July 2013
Second TextBox :- 31 December 2013
Output should be come likes :
1 July 2013
2 July 2013
3 July 2013
4 July 2013
|
|
|
30 December 2013
31 December 2013
private List<DateTime> GetRange()
{
var res = new List<DateTime>();
var start = DateTime.Parse(textBox1.Text);
var end = DateTime.Parse(textBox2.Text);
for (var date = start; date <= end; date = date.AddDays(1))
res.Add(date);
return res;
}
Firstly, convert both inputs to date object. You can use DateTime.Parse() for this.
DateTime start = DateTime.Parse("1 July 2013");
DateTime end = DateTime.Parse("31 December 2013");
Then simply loop through to the end.
while(start <= end)
{
// Output or save to DB etc
Console.WriteLine(start.ToString("d MMMMM yyyy"));
start = start.AddDays(1);
}
Why would you want to do this?
You can certainly do it, depending on the granularity with a varchar(max) field in the db and set the string to be:
string result = "";
for(int x = 0; x< (endDate - startDate).TotalDays; x++)
{
result += startDate.AddDays(x).ToDateString();
}
I can't fathom a reason why you would want this though. Store the start and end date and then use logic in the application to calculate the information as and when required would seem like it would make a lot more sense.
List<DateTime> allDates = new List<DateTime>();
int starting = startingDate.Day;
int ending = endingDate.Day;
for (int i = starting; i <= ending; i++)
{
allDates.Add(new DateTime(startingDate.Year, startingDate.Month, i));
}
using Linq:
var date1 = DateTime.Now.AddMonths(-1);
var date2 = DateTime.Now;
var dates = Enumerable
.Range(1, (int)(date2 - date1).TotalDays)
.Select(d => date1.AddDays(d).Date);
And to dump the result to a string:
var output = string.Join(Environment.NewLine, dates);
Thanks For your Response Everyone.....
but Perfect Answer for me is Combination of all above Answers...
DateTime dt = Convert.ToDateTime(TextBox1.Text);
string result = "";
for (int x = 0; x <= (Convert.ToDateTime(TextBox2.Text) - Convert.ToDateTime(TextBox1.Text)).TotalDays; x++)
{
result = dt.AddDays(x).ToString("d MMMMM yyyy");
Response.Write("<br>" + result);
}

In C#, what is the best way to find gaps in a DateTime array?

I have a list of dates that are apart by a month in the sense that all dates are the "First Monday of the month". In some cases months are missing so I need to write a function to determine if all dates are consecutive
So for example if this was the list of dates, the function would return true as all items are the "First Friday of the month" and there are no gaps. This example below would return true.
var date = new DateTime(2013, 1, 4);
var date1 = new DateTime(2013, 2, 1);
var date2 = new DateTime(2013, 3, 1);
var date3 = new DateTime(2013, 4, 5);
var dateArray = new DateTime[]{date, date1, date2, date3};
bool isConsecutive = IsThisListConsecutive(dateArray);
where this example below would return false because, even though they are also all "First Friday of the month", its missing the March 2013 item.
var date = new DateTime(2013, 1, 4);
var date1 = new DateTime(2013, 2, 1);
var date3 = new DateTime(2013, 4, 5);
var dateArray = new DateTime[]{date, date1, date3};
bool isConsecutive = IsThisListConsecutive(dateArray);
so i am trying to figure out the right logic for the IsThisListConsecutive() method:
Here was my first try: (Note I already know upfront that all dates are same day of week and same week of month so the only thing i am looking for is a missing slot)
private bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
DateTime firstDate = orderedSlots.First();
int count = 0;
foreach (var slot in orderedSlots)
{
if (slot.Month != firstDate.AddMonths(count).Month)
{
return false;
}
count++;
}
return true;
}
This code above works exept if the list crosses over from one year to another. I wanted to get any advice on a better way to create this function and how that line could be rewritten to deal with dates that cross over years.
So to implement this we'll start with a simple helper method that takes a sequence and returns a sequence of pairs that make up each item with it's previous item.
public static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> source)
{
T previous;
using (var iterator = source.GetEnumerator())
{
if (iterator.MoveNext())
previous = iterator.Current;
else
yield break;
while(iterator.MoveNext())
{
yield return Tuple.Create(previous, iterator.Current);
previous = iterator.Current;
}
}
}
We'll also use this simple method to determine if two dates are in the same month:
public static bool AreSameMonth(DateTime first, DateTime second)
{
return first.Year == second.Year
&& first.Month == second.Month;
}
Using that, we can easily grab the month of each date and see if it's the month after the previous month. If it's true for all of the pairs, then we have consecutive months.
private static bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
return orderedSlots.Pair()
.All(pair => AreSameMonth(pair.Item1.AddMonths(1), pair.Item2));
}
Note: This is completely untested, and the date checks are probably pretty bad or somewhat redundant, but that’s the best I could come up with right now ^^
public bool AreSameWeekdayEveryMonth(IEnumerable<DateTime> dates)
{
var en = dates.GetEnumerator();
if (en.MoveNext())
{
DayOfWeek weekday = en.Current.DayOfWeek;
DateTime previous = en.Current;
while (en.MoveNext())
{
DateTime d = en.Current;
if (d.DayOfWeek != weekday || d.Day > 7)
return false;
if (d.Month != previous.Month && ((d - previous).Days == 28 || (d - previous).Days == 35))
return false;
previous = d;
}
}
return true;
}
I would recommend looking at the TimeSpan structure. Thanks to operator overload you can get a TimeSpan by substracting two dates and then receive a TimeSpan that expresses the difference between the two dates.
http://msdn.microsoft.com/en-us/library/system.timespan.aspx
okay, your code doesnt work when the years cross over becuase jan 1st may be a monday on one year and a tuesday on the next. If I was doing this, I would first check that
a) they are the same day of the week in each month (use DateTime.DayOfWeek)
b) they are the same week of the month in each month*
use extension method DayOfMonth (see link)
* Calculate week of month in .NET *
(you said you already know a & b to be true so lets go on to the third condition)
c) we have to determine if they are in consecutive months
//order the list of dates & place it into an array for ease of looping
DateTime[] orderedSlots = slots.OrderBy( t => t).ToArray<DateTime>();
//create a variable to hold the date from the previous month
DateTime temp = orderedSlots[0];
for(i= 1; index < orderedSlots.Length; index++)
{
if((orderedSlots[index].Month != temp.AddMonths(1).Month |
orderedSlots[index].Year != temp.AddMonths(1).Year)){
return false;
}
previousDate = orderedSlots[index];
}
return true;
if you need to check conditions a & b as well add change the if statement as follows
if( orderedSlots[index].Month != temp.AddMonths(1).Month |
orderedSlots[index].Year != temp.AddMonths(1).Year) |
orderedSlots[index].DayOfWeek != temp.DayOfWeek |
orderedSlots[index].GetWeekOfMonth != temp.AddMonths(1).GetWeekOfMonth){
return false;
}
remember that to use the get week of month extension method you have to include the code in
Calculate week of month in .NET
I'm sure there are typos as I did this in a text editor.
Well, here is my initial thought on how I would approach this problem.
First, is to define a function that will turn the dates into the ordinal values corresponding to the order in which they should appear.
int ToOrdinal(DateTime d, DateTime baseline) {
if (d.Day <= 7
&& d.DayInWeek == baseline.DayInWeek) {
// Since there is only one "First Friday" a month, and there are
// 12 months in year we can easily compose the ordinal.
// (As per default.kramer's comment, months normalized to [0,11].)
return d.Year * 12 + (d.Month - 1);
} else {
// Was not correct "kind" of day -
// Maybe baseline is Tuesday, but d represents Wednesday or
// maybe d wasn't in the first week ..
return 0;
}
}
var dates = ..;
var baseline = dates.FirstOrDefault();
var ordinals = dates.Select(d => ToOrdinal(d, baseline));
Then, for the dates provided, we end up with ordinal sequences like:
[24156 + 0, 24156 + 1, 24156 + 2, 24156 + 3]
And
[24156 + 0, 24156 + 1, /* !!!! */ 24156 + 3]
From here it is just a trivial matter of iterating the list and ensuring that the integers occur in sequence without gaps or stalls - that is, each item/integer is exactly one more than the previous.
I could be misinterpreting what you are trying to do, but I think this will work, assuming you don't have to handle ancient dates. See if there are any gaps in the dates converted to "total months"
int totalMonths = date.Year * 12 + (date.Month - 1);

Categories

Resources