I have this challange that I finished which asked to print out a string according to the provided schedule. Here is an example:
var restaurant = new Restaurant(
new OpeningHour(8,16), // Sunday
new OpeningHour(8,17), // Monday
new OpeningHour(8,17), // Tuesday
new OpeningHour(8,17), // Wednesday
new OpeningHour(8,16), // Thursday
new OpeningHour(8,16), // Friday
new OpeningHour(8,16) // Saturday
);
expected output result = "Sun, Thu - Sat: 8-16, Mon - Wed: 8-17"
What I did was essentially:
Create a List of Days, OpenHours, and CloseHours
Create a HashSet of the days so that I can compare the days
Create a for loop according to HashSet and Days
Seperate the Start, Middle, and Ending
Concatenate the result according to the open and close hours as well as the gap between days
I have tried my best but I know for a fact that my code is not efficient at all, instead messy. I am trying to improve my C# skills please help. Here is my messy code:
namespace Livit
{
using System;
using System.Collections.Generic;
using System.Linq;
public class Restaurant
{
public WeekCollection<OpeningHour> OpeningHours { get; private set; }
public Restaurant() {
// No opening hours available for restaurant
}
public Restaurant(OpeningHour monday, OpeningHour tuesday, OpeningHour wednesday, OpeningHour thursday, OpeningHour friday, OpeningHour saturday, OpeningHour sunday)
{
OpeningHours = new WeekCollection<OpeningHour>(monday, tuesday, wednesday, thursday, friday, saturday, sunday);
}
// THE EMPHASIS OF THE CHALLANGE IS THIS FUNCTION RIGHT HERE!!!
// Parse the date into desired format
public string DateParser(List<DayOfWeek> days, List<TimeSpan> openHours, List<TimeSpan> closeHours)
{
HashSet<string> availableRanges = new HashSet<string>();
List<string> timeRanges = new List<string>();
DayOfWeek current = DayOfWeek.Sunday;
string result = "";
for (int i = 0 ; i < days.Count; i++){
string timeRange = openHours[i].ToString().Substring(1,1)+'-'+closeHours[i].ToString().Substring(0,2);
availableRanges.Add(timeRange);
timeRanges.Add(timeRange);
}
List<string> arToList= availableRanges.ToList();
for (int i = 0 ; i < arToList.Count; i++)
{
for (int j = 0 ; j < timeRanges.Count; j++){
if(timeRanges[j] == arToList[i]){
// First Item
if(j==0 ){
result += days[j].ToString().Substring(0,3);
}
// Last Item
else if(j==timeRanges.Count-1){
char last = result.Last();
if(last != ' '){
result += " - ";
}
result += days[j].ToString().Substring(0,3);
}
// Everything in the middle
else{
if(days[j]-current > 1){
result += ", ";
}
if(timeRanges[j] != timeRanges[j-1] ){
result += days[j].ToString().Substring(0,3);
} else if (timeRanges[j] == timeRanges[j-1]){
char last = result.Last();
if(last != ' '){
result += " - ";
}
if(timeRanges[j] != timeRanges[j+1]){
result += days[j].ToString().Substring(0,3);
}
}
}
current = days[j];
}
}
result += ": " + arToList[i];
if(i!=arToList.Count-1){
result += ", ";
}
}
Console.WriteLine(result);
return result;
}
public string GetOpeningHours()
{
// Declare List for each attribute
List<DayOfWeek> days = new List<DayOfWeek>();
List<TimeSpan> openHours = new List<TimeSpan>();
List<TimeSpan> closeHours = new List<TimeSpan>();
// Call the opening and closing hours from each day and feed into new array
foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)).OfType<DayOfWeek>().ToList()) {
TimeSpan openHour = OpeningHours.Get(day).OpeningTime;
TimeSpan closeHour = OpeningHours.Get(day).ClosingTime;
days.Add(day);
openHours.Add(openHour);
closeHours.Add(closeHour);
}
return DateParser(days,openHours,closeHours);
throw new NotImplementedException();
}
}
public class OpeningHour
{
public TimeSpan OpeningTime { get; private set; }
public TimeSpan ClosingTime { get; private set; }
public OpeningHour(TimeSpan openingTime, TimeSpan closingTime)
{
OpeningTime = openingTime;
ClosingTime = closingTime;
}
public OpeningHour(int openingHour, int closingHour)
{
OpeningTime = TimeSpan.FromHours(openingHour);
ClosingTime = TimeSpan.FromHours(closingHour);
}
}
public class WeekCollection<T>
{
private Dictionary<DayOfWeek, T> _collection;
public WeekCollection(T sunday, T monday, T tuesday, T wednesday, T thursday, T friday, T saturday)
{
_collection = new Dictionary<DayOfWeek, T>();
_collection.Add(DayOfWeek.Sunday, sunday);
_collection.Add(DayOfWeek.Monday, monday);
_collection.Add(DayOfWeek.Tuesday, tuesday);
_collection.Add(DayOfWeek.Wednesday, wednesday);
_collection.Add(DayOfWeek.Thursday, thursday);
_collection.Add(DayOfWeek.Friday, friday);
_collection.Add(DayOfWeek.Saturday, saturday);
}
public T Get(DayOfWeek dayOfWeek)
{
return _collection[dayOfWeek];
}
}
}
Currently, I am still trying to find a better way in doing this challange. Any help would be appriciated.
P.S. I highlighted the part where my concatenation is occuring, this part is basically the emphasis of the whole challange
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)));
I'm the head in the refacto of my code because it's a mess.
But since I'm on it from yesterday, my head look like a stone -_-"
#region DateTime foreach Currencies
static DateTime eurusd = DateTime.Now.AddHours(-1);
static DateTime eurgbp = DateTime.Now.AddHours(-1);
static DateTime eurjpy = DateTime.Now.AddHours(-1);
static DateTime usdjpy = DateTime.Now.AddHours(-1);
static DateTime gbpjpy = DateTime.Now.AddHours(-1);
static DateTime gbpusd = DateTime.Now.AddHours(-1);
static DateTime eurusdm1 = DateTime.Now.AddHours(-1);
static DateTime eurgbpm1 = DateTime.Now.AddHours(-1);
static DateTime eurjpym1 = DateTime.Now.AddHours(-1);
static DateTime usdjpym1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpym1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdm1 = DateTime.Now.AddHours(-1);
static DateTime eurusdh1 = DateTime.Now.AddHours(-1);
static DateTime eurgbph1 = DateTime.Now.AddHours(-1);
static DateTime eurjpyh1 = DateTime.Now.AddHours(-1);
static DateTime usdjpyh1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpyh1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdh1 = DateTime.Now.AddHours(-1);
static DateTime eurusdd1 = DateTime.Now.AddHours(-1);
static DateTime eurgbpd1 = DateTime.Now.AddHours(-1);
static DateTime eurjpyd1 = DateTime.Now.AddHours(-1);
static DateTime usdjpyd1 = DateTime.Now.AddHours(-1);
static DateTime gbpjpyd1 = DateTime.Now.AddHours(-1);
static DateTime gbpusdd1 = DateTime.Now.AddHours(-1);
#endregion
There are 24 different DateTime.
switch (data.Instrument)
{
case "EUR/USD":
if (CanUpdate(ref eurusd, "s5"))
{ InsertData("eurusd", data); }
if (CanUpdate(ref eurusdm1, "m1"))
{ InsertData("eurusdm1", data);}
if (CanUpdate(ref eurusdh1, "h1"))
{ InsertData("eurusdh1", data);}
if (CanUpdate(ref eurusdd1, "d1"))
{ InsertData("eurusdd1", data);}
}
A switch case with 6 Case (like the one above)
(InsertData just put some object in a collection. "x" => collection name, data => the object)
private bool CanUpdate(ref DateTime date, string timer)
{
TimeSpan result = DateTime.Now - date;
if (timer == "s5")
{
int difSeconds = result.Seconds;
if (difSeconds >= 5)
{
date = DateTime.Now;
return true;
}
}
if (timer == "m1")
{
int difMinutes = result.Minutes;
if (difMinutes >= 1)
{
date = DateTime.Now;
return true;
}
}
if (timer == "h1")
{
int difHour = result.Hours;
if (difHour >= 1)
{
date = DateTime.Now;
return true;
}
}
if (timer == "d1")
{
int difDays = result.Days;
if (difDays >= 1)
{
date = DateTime.Now;
return true;
}
}
return false;
}
My "CanUpdate" Method. Check the time between the last update and if the "if condition" are true it update the "date variable" and return true, else it return false.
As you can guess, this switchcase have more or less 70 lines. One change need to be repercuted on the whole switchcase. Ugly right ?
I would like to get rid of this switchcase and make it more maintainable.
I've think about put all of the data in different list.
So it will look like:
List<String> collectionName;
List<DateTime> dateTime;
List<String> timeFrame;
and do a foreach on the DateTime collection then do 2 nested for.
Somthing like:
foreach (DateTime dt in dateTime)
{
for(i=0; i <= collectionName.Lenght; i++)
{
for(j=0; j <= timeFrame.Lenght; j++)
{
CanUpdate(ref dt, timeFrame[j])
InsertData(collectionName[i].ToString(), data)
}
}
}
Am I in the right direction and do you even understand what I would like. Because if your head are in the same state as mine after reading this. Sorry :O
Preamble
I would (and, in fact, I did) use Dictionary to solve this problem.
I'm not a big fan of Tuple. So, for real application I would create some struct/class instead.
For the answer I assume that it's required to work with strings of formats "EUR/USD" and "eurusdm1" (see method GetInsertDataArgument()).
Of course, I haven't tested the code :) But I think it's more than enough to get the idea.
I've decided to make all the members static because you had your datetimes static in the original code. You can easily change this.
Code
class MyClass
{
private static readonly Dictionary<Tuple<string, string>, DateTime> lastUpdateDateTimes = new Dictionary<Tuple<string, string>, DateTime>();
private static readonly Dictionary<string, TimeSpan> timeIntervals = new Dictionary<string, TimeSpan>();
static MyClass()
{
timeIntervals.Add("s5", TimeSpan.FromSeconds(5));
timeIntervals.Add("m1", TimeSpan.FromMinutes(1));
timeIntervals.Add("h1", TimeSpan.FromHours(1));
timeIntervals.Add("d1", TimeSpan.FromDays(1));
}
private static string GetInsertDataArgument(string instrument, string timeIntervalName)
{
string result = instrument.Replace("/", "").ToLower();
if (timeIntervalName != "s5")
result = result + timeIntervalName;
return result;
}
private static void Update(string instrument)
{
DateTime now = DateTime.Now;
foreach (var timeInterval in timeIntervals)
{
var dateTimeKey = new Tuple<string, string>(instrument, timeInterval.Key);
if (now - lastUpdateDateTimes[dateTimeKey] < timeInterval.Value)
continue;
lastUpdateDateTimes[dateTimeKey] = now;
InsertData(GetInsertDataArgument(instrument, timeInterval.Key), data);
}
}
}
What's going on
There are 2 dictionaries:
lastUpdateDateTimes stores datetimes for each currency pair and time interval. First member of tuple stores currency pair (in "EUR/USD" format), second member stores time interval name (in "s5" format).
timeIntervals holds your time intervals. It is filled in static constructor of class.
Update method is the replacement for your switch statement and CanUpdate method.
Thanks you. Your idea are really good.
exactly what I needed especially the:
Dictionnary<Tuple<string,string>,DateTime>
I was wondering how to make all those data relational.
I just needed to delete the
if (timeIntervalName != "s5")
because
"result = result + timeIntervalName;"
should be trigger every time GetArgumentName are called.
Neded to make a
TimeSpan timeElapsed = now - lastUpdateDateTimes[dateTimeKey];
Because it didn't work in the condition even between (). Don't know why, it should.(?)
And I also needed to populate my lastUpdateDateTimes Dictionnary. (ofc)
So, thank you again. Work like a charm.
I want to extract all the sundays in the current month and have this code:
private string GetDatesOfSundays(DateTime DatMonth)
{
string sReturn = "";
int iDayOffset = DatMonth.Day - 1;
DatMonth = DatMonth.AddDays(System.Convert.ToDouble(-DatMonth.Day + 1));
DateTime DatMonth2 = DatMonth.AddMonths(1).AddDays(System.Convert.ToDouble(-1));
while (DatMonth < DatMonth2)
{
if (DatMonth.DayOfWeek == System.DayOfWeek.Sunday)
{
if (sReturn.Length > 0) sReturn += ",";
sReturn += DatMonth.ToShortDateString();
}
DatMonth = DatMonth.AddDays(1.0);
}
return sReturn;
}
[HttpGet]
public ActionResult TradeUKKPISearchesData()
{
string allSundaysInMonth = GetDatesOfSundays(System.DateTime.Now);
//var reportData = _reportingService.GetTradeUKKPISearches();
//return View(reportData);
}
the problem lies with my type string for allSundaysInMonth and is also empty ofcourse. The sReturn is of type string but then again I pass a date(I know :) ) but what type should allSundaysInMonth be? sReturn does have the correct dates in...I need to display these dates in a dropdown in the view of the controller so the user can select any of the sundays for which he/she needs to run a report for.
thanks
How about
private IEnumerable<DateTime> GetDatesOfSundays(DateTime DatMonth)
{
int iDayOffset = DatMonth.Day - 1;
DatMonth = DatMonth.AddDays(System.Convert.ToDouble(-DatMonth.Day + 1));
DateTime DatMonth2 =
DatMonth.AddMonths(1).AddDays(System.Convert.ToDouble(-1));
while (DatMonth < DatMonth2)
{
if (DatMonth.DayOfWeek == System.DayOfWeek.Sunday)
{
yield return DatMonth;
}
DatMonth = DatMonth.AddDays(1.0);
}
}
I would be tempted to rewrite your function as an extension somthing like this
public static IEnumerable<Datetime> DaysOfMonth(
this DateTime any,
DayOfWeek day)
{
// start at first of month
var candidate = new DateTime(any.Year, any.Month, 1);
var offset = (int)day - (int)candidate.DayOfWeek;
if (offset < 0)
{
offset += 7
}
candidate = candidate.AddDays(offset);
while (cadidate.Month == any.Month)
{
yield return candidate;
candidate = candidate.AddDays(7.0)
}
}
Then you could use it like this
var allSundaysInMonth = DateTime.Now.DaysOfMonth(DayOfWeek.Sunday);
If you want to convert an IEnumerable<DateTime> to a string you could do this,
var listOfDates = string.Join<DateTime>(", ", allSundaysInMonth);
using this string.Join overload
If you really want the days as a DateTime[] you could do this (but there is no need)
DateTime[] allSundaysInMonth = GetDatesOfSundays(DateTime.Now).ToArray();
or for my extension example
var allSundaysInMonth = DateTime.Now.DaysOfMonth(DayOfWeek.Sunday).ToArray();
You can go for DateTime[] or IEnumerable<DateTime>.
Your method signature should be
private IEnumerable<DateTime> GetDatesOfSundays(DateTime DatMonth)
or
private DateTime[] GetDatesOfSundays(DateTime DatMonth)
If you havn't worked with IEnumerable go for this
private DateTime[] GetDatesOfSundays(DateTime DatMonth)
{
List<DateTime> lst = new List<DateTime>();
DatMonth = DatMonth.AddDays(-DatMonth.Day + 1);
DateTime DatMonth2 = DatMonth.AddMonths(1).AddDays(System.Convert.ToDouble(-1));
while (DatMonth < DatMonth2)
{
if (DatMonth.DayOfWeek == System.DayOfWeek.Sunday)
{
lst.Add(DatMonth);
DatMonth = DatMonth.AddDays(7);
continue;
}
DatMonth = DatMonth.AddDays(1);
}
return lst.ToArray();
}
and call it as
DateTime[] allSundaysInMonth = GetDatesOfSundays(System.DateTime.Now);
I'm trying to make a calendar using wpf. By using itemsPanel and more, I have a grid with 7 columns(sunday-saturday) and 6 rows(week# of month). If i can find the starting position of the first of each month by getting the weekday and week number(of the month), how can I find the week number(0-5 of each month)? Also can't I somehow just fill in the calendar from there? I'm lost and I don't know what else to try.
public partial class SchedulePage : Page
{
MainWindow _parentForm;
public int dayofweek;
public SchedulePage(MainWindow parentForm)
{
InitializeComponent();
_parentForm = parentForm;
// DateTime date = new DateTime(year, month, day);
_parentForm.bindings = new BindingCamper();
_parentForm.bindings.schedule.Add(new Schedule { WeekNo = (int) getWeekNumber(), WeekDay = dayofweek });
DataContext = _parentForm.bindings;
// lblTest.Content = dates(2011, 10, 27);
}
public double getWeekNumber()
{
dayofweek = getWeekDay(2011, 10, 31);
double h = dayofweek / 7;
double g = Math.Floor(h);
return g;
}
public int getWeekDay(int year, int month, int day)
{
//year = 2011;
//month = 10;
//day = 27;
int[] t = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
// year -= month < 3;
return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7;
}
You must use Calendar.GetDayOfWeek and Calendar.GetWeekOfYear in preference to writing yourself.
You can guarantee that if you write any date / time handling code yourself it will contain faults and won't work in different locales.
public class Row
{
public string MonthWeek { get; set; }
public string Year { get; set; }
public string Month { get; set; }
public string Day { get; set; }
public string WeekOfYear { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var l = new List<Row>();
DateTime startDate = DateTime.Now;
DateTime d = new DateTime(startDate.Year, startDate.Month, 1);
var cal = System.Globalization.DateTimeFormatInfo.CurrentInfo.Calendar;
var ms = cal.GetWeekOfYear(new DateTime(d.Year, d.Month, 1), System.Globalization.CalendarWeekRule.FirstDay, System.DayOfWeek.Sunday);
for (var i = 1; d.Month == startDate.Month; d = d.AddDays(1))
{
var si = new Row();
var month_week = (d.Day / 7) + 1;
si.MonthWeek = month_week.ToString();
si.Month = d.Year.ToString();
si.Year = d.Month.ToString();
si.Day = d.Day.ToString();
si.WeekOfYear = cal.GetWeekOfYear(d, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString();
l.Add(si);
}
dataGrid1.ItemsSource = l;
}
}
together with the obligatory DataGrid in the XAML:
<DataGrid AutoGenerateColumns="true" Name="dataGrid1" />
You can use Calendar.GetWeekOfYear from Globalization to do this.
Here's the MSDN docs for it: http://msdn.microsoft.com/en-us/library/system.globalization.calendar.getweekofyear.aspx
You should pass the appropriate culture properties from CultureInfo.CurrentCulture to GetWeekOfYear so that you match the current culture properly.
Example:
int GetWeekOfYear(DateTime date)
{
return Calendar.GetWeekOfYear(
date,
CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule,
CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek
);
}
You could easily modify this into an extension method on DateTime:
static int GetWeekOfYear(this DateTime date)
{
return Calendar.GetWeekOfYear(
date,
CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule,
CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek
);
}
With #Polynomial answer, I have this error:
An object reference is required for the non-static field, method, or property...
If you instanciate GregorianCalendar before then you can call the method GetWeekOfYear !
private static int GetWeekNumber(DateTime time)
{
GregorianCalendar cal = new GregorianCalendar();
int week = cal.GetWeekOfYear(time, CalendarWeekRule.FirstFullWeek, DayOfWeek.Monday);
return week;
}