Store DayOfWeek data in SQL Server - c#

I want to save the DayOfWeek data as a column in a SQL Server table. Is this possible? ATM I'm saving an int and converting to DayOfWeek with a switch method, but I wish I could save and retrieve the data directly from the database.
UPDATE
I will try to explain. The user creates a recurring event, usually 2 times a week, for example, Monday and Friday. I want to create (on code run) all the recurring events in a given month, SO I want to store the DayOfWeek in SQL because for every event user can register if another user were present, late or so on..
Here a part of the code:
public static List<int> GetAttendance(int year, int month, DayOfWeek doW_1, DayOfWeek doW_2)
{
var days = DateTime.DaysInMonth(year, month);
var attendances = new List<int>();
for (int currentDay = 1; currentDay <= days; currentDay++)
{
var day = new DateTime(year, month, currentDay);
if (day.DayOfWeek == doW_1 || day.DayOfWeek == doW_2)
{
attendances.Add(currentDay);
}
}
return attendances;
}
doW1 and 2 comes from a little converter method made by me who read in db the integer stored by the user to create the recurring events.
UPDATE 2: I want to store data this way because I will use them for PREDICT future events by user inputs. Clear now?

You have two options.
Store your date value in a Date or DateTime columns and when querying, write queries with a where clause something like
WHERE DATENAME(WEEKDAY, DateColumn ) = 'Sunday'
But this will not be a sargable expression and on bigger data sets the query performance will be bad.
You can also store the week day in a Varchar(9) column and again use DATENAME() to extract the Week Day name from your date values at the time of Insert/update.
You can index this column and write simple queries like
SELECT * FROM Table
WHERE DateColumName = 'Sunday'
This option is commonly used in data warehouse environment where reducing data redundancy is not the goal but best read performance is the goal.

Keep storing it as an int, but you can get rid of your switch by just casting your saved int like so:
DayOfWeek day = DayOfWeek.Friday;
int temp = (int)day;
day = (DayOfWeek)temp;
Console.WriteLine(day); // Friday

Save it as a Date Column and use the following SQL functions to parse the WeekDay ID or WeekDay Name.
Using a date keeps your data structure understandable.
SELECT Datepart(weekday, Getdate())
SELECT Datename(weekday, Getdate())

Related

Update 2 million rows for 1 column

I have a table with approximately 2 million records. I have to loop through each record and update the effective date. I need to set the day to the first of the month for each date.
If the current date is the first of the month, then ignore.
i.e.
07/01/2018
07/21/2018 => 07/01/2018
08/11/2018 => 08/01/2018
Currently, I'm writing this as a C# program and it taking way too long.
Is there a better solution?
Just use DATEADD() and DATEDIFF() combination to get the first of the month date
UPDATE t
SET datecol = DATEADD(MONTH, DATEDIFF(MONTH, '1900-01-01', datecol), '1900-01-01')
FROM yourtable t;
It could be as simple as:
Update myTable
set myDate = DateAdd(day, 1-Day(myDate), myDate)
where day(myDate) > 1;

Using sql to add to dates during a query

I have a table that keeps track of when particular events occur, and how long they last. For reasons I cannot fathom, it was designed to store the start date of the event, start time of the event, then the number of hours and minutes the event lasted. Like this:
EventStartDate | EventStartTime | TimeSpentHours | TimeSpentMinutes
Where EventStartDate is a dateTime with the hours/minutes always set to zero, so that, even though it's a date time, all the values are like "12/22/2016 00:00". The EventStartTime is a char(4) which is military time of the start of the event. TimeSpentHours is and int which is the total hours the event duration, and TimeSpentMinutes is an int for the number of minutes. Obviously the total time spent for the event is the hours plus the minutes.
The problem: I need to be able to, given a particular DateTime, find all the events that were occuring during that time. Put another way, given a particular DateTime I need to get all the events with a starting date and time that's greater than or equal to the given DateTime and less than or equal to an "end" date and time.
So I need to compute the "EndDateTime" based off the values in the database during the query. The database is SqlServer 2008 R2. I am using C# for WinForm application to query the data.
So far I have roughly:
public static List<ImportantEvents> GetEventsDuringDateTime(DateTime timeOfEvent)
{
using (SqlConnection sqlConn = getAndOpenSqlConn())
{
string theEventTime = timeOfEvent.ToString("hhmm");
string sqlStmt = "SELECT EVENT_ID, AGENCY, EVENTSTARTDATE, ACTNOTE, EVENTSTARTTIME, TIMESPENTHOURS, TIMESPENTMINUTES FROM EVENTSMAIN WHERE((EVENTSTARTDATE<= #MYEVENTDATETIME AND EVENTSTART TIME< #ACTTIME) AND ...";"
}
}
(the above SQL obviously won't work and is where I am stuck...)
My question is: how can I, in the query, add the EVENTSTARTTIME to the EVENTSTARTDATE to create a new "temporary" column, then add the TIMESPENTHOURS and TIMESPENTMINUTES to that column into another new "temporary" column, to then query against given a specific DateTime value???
It is possible to achieve this in a single query with a common-table expression like this:
With StartAndEndTimes As (
Select Event_ID,
EventStart = DateAdd(Minute, Convert(int, Right(EventStartTime, 2)), DateAdd(Hour, Convert(int, Left(EventStartTime, 2)), EventStartDate)),
EventEnd = DateAdd(Minute, Convert(int, Right(EventStartTime, 2))+TimeSpentMinutes, DateAdd(Hour, Convert(int, Left(EventStartTime, 2))+TimeSpentHours, EventStartDate))
From EventsMain)
Select Event_Id, EventStart, EventEnd, <<add other fields here>>
From StartAndEndTimes
Where EventStart <= #MyEventDateTime
And EventEnd > #MyEventDateTime;
Basically you can extract the hours and minutes from the start time and add them to the start date to get a true, datetime, start date. Similar with the end date. It is not necessary to use common-table expression here, but it does make the code more readable. Then you just do the ordinary date comparison to your input parameter.
Here I have disected parts of the final query. You will need to put the final part into your query wherever you need it.
SELECT Combined = EVENTSTARTDATE + EVENTSTARTTIMEFROM FROM EventsMain
SELECT CombinedWithHour = DATEADD(hh, TIMESPENTHOURS, Combined) FROM EventsMain
SELECT CombinedWithMinute = DATEADD(mi, TIMESPENTMINUTES, CombinedWithHour) FROM EventsMain
All together:
SELECT DATEADD(mi, TIMESPENTMINUTES, DATEADD(hh, TIMESPENTHOURS, EVENTSTARTDATE + EVENTSTARTTIME)) FROM EventsMain

return date without time but not of type string but date

I have a date value that I want to strip the time from. I want the return type to be a date type since I want to order the list of date I have. having a list to string representing Date does not return a correct order.
I know that DateTime always returns the date with the time. What are my options here? How can I better my code and have a list of items of Date type without the time?
Edit: I would like to have the date only. nothing after that. Something like 8/7/2016 not 8/7/2016 00:00:00 or anything after date. and in a date object.
Here is my code:
using (var db = new MyModel.Context())
{
var cert = (
from tr in db.uspTranscripts(personId)
from a in db.PersonTranscripts.Where(x => x.UPID == personId)
from b in db.LU_CreditType.Where(x => x.ID == a.CreditTypeID)
select new CertViewModel
{
ActivityTitle = tr.ActivityTitle,
Score = tr.Score,
Status = tr.Status,
CompletionDate = tr.CompletionDate,
CretitTypeName = b.ShortName,
CompletedDateSorted = a.HK_CreatedOn
}).OrderByDescending(x => x.CompletedDateSorted).ToList();
List<CertViewModel> certlist = cert;
foreach (var item in certlist)
{
string itemWithoutHour = item.CompletionDate.Value.ToShortDateString();
var itemConverted = DateTime.ParseExact(itemWithoutHour, "M/d/yyyy", null);
item.CompletionDate = itemConverted;
}
return certificateslist.GroupBy(x => x.ActivityTitle).Select(e => e.First()).ToList();
}
For any given DateTime object, you can reference its Date property to strip out the time values:
var withTime = DateTime.Now; // 8/7/2016 22:11:43
var withoutTime = withTime.Date; // 8/7/2016 00:00:00
The .NET framework does not have a date-only object.
It may be worth understanding how the DateTime structure works. Internally, it stores an offset in ticks (1 tick = 100 nanoseconds) since 1/01/0001 12:00 am in a single 64-bit unsigned integer. (1 tick = 100 nanoseconds)
The DateTime structure then provides many useful methods and properties for dealing with dates and times, such as adding some days to an existing date, or calculating the difference of two times. One useful property is Date, which rounds a DateTime object down to the nearest day (12:00 am).
Dates, times and dates-with-times are all very similar, the main difference is how you format them, a date-with-time where you omit the time is just a date.
What David has suggested is that you work with the DateTime structure internally, strip any times using the Date property, sort on the DateTime, compare them and modify them as DateTime objects.
Only convert them to a string when they need to be displayed, at which point you can use methods such as ToShortDateString() or ToString(string format) to display only the date.

How can I plot recurring data on a datetime month axis in c#

I am working on a basic budgeting app for Windows in c#. I have an SQL table which stores a list of incomes and a table which stores expenses. In both cases the user selects whether this is a daily/weekly/monthly amount and a date for this income/expense.
I have managed to create a line series chart which displays the total of all amounts per month, with Month on the x-axis, using the following code:
var query = conn.Table<incomedata>();
LineSeries IncomeLineSeries = new LineSeries();
List<DateAmountList> List1 = new List<DateAmountList>();
for (int i = 1; i <= 12; i++)
{
List1.Add(new DateAmountList() { Date = DateTimeFormatInfo.CurrentInfo.GetMonthName(i), Amount = query.AsEnumerable()
.Where(o => CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(o.Date.Month) == DateTimeFormatInfo.CurrentInfo.GetMonthName(i)).Sum(o => (int)o.Amount) });
}
IncomeLineSeries.ItemsSource = List1;
IncomeLine.Series.Add(IncomeLineSeries);
I know that I could make the user choose an end date and from that work out how many months to repeat for, but I'm stuck on how to add that amount to the total for every month and display it...
So for example you earn 100 every month for 12 months starting from January, at the moment the amount is only added to January as that is the stored datetime, how can I add 100 to every month of the DateAmountList (Amount) for as long as it recurs?
Once I have an idea of how to do it monthly, I'll apply similar logic to daily and weekly.
I eventually figured out to do this I could populate another table with the amount stored against each month and add to the table for each month, then just add to a chart series

Linq datetime compare in where clause

I have a table with a couple of columns called Key and Value.
One of the Keys is called RequestedOn and the value is a timestamp saved as a string.
Now in my linq query I would like to compare this timestamp, for example
var startDate = DateTime.Now.AddDays(-7);
var endDate = DateTime.Now;
var query = (from ep in db.ExtendedProperties
where
ep.Key == "RequestedOn" && ep.Value >= startDate && ep.Value <= endDate
select ep).ToList();
Now I know I cannot compare ep.Value (string) against startDate or endDate, and I cannot convert ep.Value to a DateTime as it couldn't make sense. Any ideas on a solution?
Thanks in advance?
if its saved as string you must parse it to DateTime and then compare
You can either:
Convert the DateTime to string
Convert the string to DateTime
Write a method that compares the 2 directly
Something else
Using LINQ for something that does not have a type and contains different data is not a good option. The whole point of LINQ is to have types.
That being said one solution to your problem is to save the date in a format that is comparable as string such as 201405231801 (being 23.05.2014 18:01) and just compare strings.
Of course you care about timezones and daylight saving time you are guaranteed to get it wrong.
If you save your strings right you can actually do a comparison:
For example: '20131201125959': year, month, date, hours, minutes, seconds.

Categories

Resources