What i want to do is to create a simple calendar, and I want to find the first day of the first week of a specific month. My calendar is a Monday -> Sunday calendar and the following code works, but as you can see it's not that nice. Anyone have any better idea on how to get the first date in the calendar.
var now = new DateTime(Year, Month, 1);
now = now.AddDays(1-(int)now.DayOfWeek);
now = now.Day > 15 ? now : now.AddDays(-7);
The calendar will end up looking like this:
| < | Jan 2011 | > |
------------------------------------
| Mo | Tu | We | Th | Fr | Sa | Su |
|[27]| 28 | 29 | 30 | 31 | 01 | 02 |
| 03 | 04 | 05 | 06 | 07 | 08 | 09 |
| .. | .. | .. | .. | .. | .. | .. |
| .. | .. | .. | .. | .. | .. | .. |
| 31 | 01 | 02 | 03 | 04 | 05 | 06 |
And in this "image" it's the [27] date that i'm trying to find.
Solution (Found i better/cleaner to loop then calculate):
public DateTime FirstDay()
{
var date = new DateTime(Date.Year, Date.Month, 1);
while (true)
{
if (date.DayOfWeek == DayOfWeek.Monday)
return date;
date = date.AddDays(-1);
}
return date;
}
public DateTime LastDay()
{
var date = new DateTime(Date.Year, Date.Month,
DateTime.DaysInMonth(Date.Year, Date.Month));
while (true)
{
if (date.DayOfWeek == DayOfWeek.Sunday)
return date;
date = date.AddDays(1);
}
return date;
}
/BR
Andreas
I would just do this. It is so easy to understand:
var firstDayOfMonth = new DateTime(year, month, 1);
DateTime startOfCalendar =
FirstDayOfWeekOnOrBefore(
firstDayOfMonth,
DayOfWeek.Monday
);
public static DateTime FirstDayOfWeekOnOrBefore(
DateTime date,
DayOfWeek dayOfWeek
) {
while(date.DayOfWeek != dayOfWeek) {
date = date.AddDays(-1);
}
return date;
}
Additionally, if you want to change your calendar to start on something other than Monday, it's trivial now. A solution using modulo arithmetic would not be as maintainable.
You can use modulo to calculate the number of filler days without a conditional statement:
DateTime firstOfMonth=new DateTime(year,month,1);
var weekDay=firstOfMonth.DayOfWeek;
int fillerDays=((int)weekDay+6)%7;
DateTime firstDayInCalendar=firstOfMonth.AddDays(-fillerDays);
You can try this assuming first day ur referring to is Monday
DateTime dt = new DateTime(2011, 2, 2);
Console.WriteLine(dt.AddDays((8 - (int)dt.DayOfWeek) % 7));
I do not like while loops, because they are expensive when used with LINQ
Hope someone else can reuse this code: (if you are in the USA, then just remove [ + 6) % 7)] in two lines)
/// <summary>
/// Expands the month.
/// | < | Jan 2011 | > |
/// ------------------------------------
/// | Mo | Tu | We | Th | Fr | Sa | Su |
/// |[27]| 28 | 29 | 30 | 31 | 01 | 02 |
/// | 03 | 04 | 05 | 06 | 07 | 08 | 09 |
/// | .. | .. | .. | .. | .. | .. | .. |
/// | .. | .. | .. | .. | .. | .. | .. |
/// | 31 | 01 | 02 | 03 | 04 | 05 | 06 |
/// </summary>
/// <param name="start">Some day in the month of interest, the start date is updated to become the date of firstDayInCalendar</param>
/// <returns>The number of days to show. This value is either (28, 35 or 42)</returns>
public static int ExpandMonth(ref DateTime start)
{
DateTime first = new DateTime(start.Year, start.Month, 1);
DateTime last = new DateTime(start.Year, start.Month, DateTime.DaysInMonth(start.Year, start.Month));
start = first.AddDays(-((int)first.DayOfWeek + 6) % 7);
last = last.AddDays(7 - ((int)last.DayOfWeek + 6) % 7);
return last.Subtract(start).Days;
}
//Thomas
I found myself needing to do this quite often, so I created the following extension method.
public static DateTime FirstDateOfCalendarMonth(this DateTime dt, DayOfWeek firstDayOfWeek = DayOfWeek.Sunday)
{
dt = new DateTime(dt.Year, dt.Month, 1);
while (dt.DayOfWeek != firstDayOfWeek){
dt = dt.AddDays(-1);
}
return dt;
}
Use it like this
var firstCalDate = DateTime.Now.FirstDateOfCalendarMonth();
It defaults to Sunday as the first DayOfWeek, but you can pass it whatever DayOfWeek you like, like this:
var firstCalDate = DateTime.Now.FirstDateOfCalendarMonth(DayOfWeek.Monday);
DateTime start_date = Cal_start_date.SelectedDate;
DateTime end_date = Cal_end_date.SelectedDate;
Dictionary<string, int> dic_week_day = new Dictionary<string, int>();
dic_week_day["Sunday"] = 1;
dic_week_day["Monday"] = 2;
dic_week_day["Tuesday"] = 3;
dic_week_day["Wednesday"] = 4;
dic_week_day["Thursday"] = 5;
dic_week_day["Friday"] = 6;
dic_week_day["Saturday"] = 7;
DateTime first_day = start_date.AddDays(1 - start_date.Day);
int selected_day = dic_week_day[Drp_day_of_week.SelectedValue.ToString()];
string str_html = "";
for (DateTime i = first_day; i <= end_date; i = i.AddMonths(1))
{
int day_of_week = dic_week_day[i.DayOfWeek.ToString()];
DateTime temp_date;
if (day_of_week > selected_day)
{
temp_date = i.AddDays((7 - day_of_week) + selected_day);
}
else
{
temp_date = i.AddDays(selected_day - day_of_week);
}
DateTime last_day_of_month = (temp_date.AddMonths(1)).AddDays(-temp_date.Day);
if (Drp_occurrence.SelectedValue.ToString() == "odd")
{
if (start_date <= temp_date && temp_date <= end_date && temp_date <= last_day_of_month)
{
str_html += "<br />" + temp_date.ToString();
}
DateTime res_date = temp_date.AddDays(14);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
res_date = temp_date.AddDays(28);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
}
else if (Drp_occurrence.SelectedValue.ToString() == "even")
{
DateTime res_date = temp_date.AddDays(7);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += "<br />" + res_date.ToString();
}
res_date = temp_date.AddDays(21);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += " , " + res_date.ToString();
}
}
else
{
int occurrence = Int32.Parse(Drp_occurrence.SelectedValue.ToString());
DateTime res_date = temp_date.AddDays((occurrence - 1) * 7);
if (start_date <= res_date && res_date <= end_date && res_date <= last_day_of_month)
{
str_html += "<br />" + res_date.ToString();
}
}
}
Div_result.InnerHtml = str_html;
UPDATE: Following code has a bug! Use modulo arithmetic, to compensate the circumstance, .NET begins the week on sunday! See other solutions here (without the one with an extra function).
If you need to find the "27" (i.e. the first day for the display of a month) simply use this:
DateTime monthStart = new DateTime(year, month, 1);
DateTime monthDisplayStart = monthStart.AddDays(-((int)monthStart.DayOfWeek - 1));
Related
My problem: I need to add 'overtime' for all previous months from the beginning of the year to the month selected.
My table in SQL Server:
Overtime : varchar(20)
Id | Login | Year | Month | Day | Overtime
---+-------+------+-------+-----+----------
1 | MIPA | 2020 | 1 | 1 | 08:00
2 | MIPA | 2020 | 1 | 2 | 08:00
3 | MIPA | 2020 | 1 | 3 | 07:30
4 | MIPA | 2020 | 1 | 4 | 12:00
...
30 | MIPA | 2020 | 1 | 30 | 04:00
...
41 | MIPA | 2020 | 2 | 1 | 08:00
42 | MIPA | 2020 | 2 | 2 | 08:00
43 | MIPA | 2020 | 2 | 3 | 07:30
44 | MIPA | 2020 | 2 | 4 | 12:00
...
52 | MIPA | 2020 | 2 | 25 | 04:00
So if the user chose March (3) and year 2020 (in dropdownlist), this function must extract the aggregated information from the overtime column of the previous months of the selected year.
(that is, in the example for January (1) and February (2) and for 2020)
Controller:
[HttpPost]
public async Task<ActionResult> PartialTableEcp() //change nothing
{
// Data is already extracted from other operations
// So e.g. user enters chooses year: 2020 month: March (3)
int numberMonth= 3;
int numberYear= 2020;
int numberOfDays= 31;
// person identification by login
var userName = _httpContextAccessor.HttpContext.User.Identity.Name;
// retrieve all month records from the table, (i dont know it works)
var existingRecords = _tableEcpContext.Karta
.Where(x => x.Login == userName &&
x.Year == numberYear &&
x.Month == numberMonth-1) ////will mathematical calculation work here?
.Select(i => new { i.Overtime })
.ToList();
// and now here is a problem how to sum all these values ..
// preferably in HHH: mm format
var thisValue = that this value would be written to the variable var;
var viewModel = new ParentView { Model1 = karta };
return PartialView("_TableViewEcp", viewModel); //change nothing
}
Model:
public partial class Karta_Model
{
[Key]
public int Id { get; set; }
public string? Login { get; set; }
public int Year { get; set; }
public int Month{ get; set; }
public int? DayOfMonth { get; set; }
public string? Overtime { get; set; }
}
public partial class ParentView
{
public List<Karta_Model> Model1 { get; set; }
}
Does anyone have any idea?
Change your select to parse the strings to TimeSpans
.Select(i => string.IsNullOrEmpty(i) ? TimeSpan.Zero : TimeSpan.Parse(i))
Then you can use Aggregate to sum the TimeSpans
.Aggregate(TimeSpan.Zero, (t1, t2) => t1 + t2)
dotnetfiddle
Am I fundamentally misunderstanding how HasFlags works? I cannot understand why this code is failing.
This code takes a value and determines if it is a valid combination of values of my Enum.
Two sub groups of Enum values are identified by ORing other members: JustTheMonths and Exclusives. JustTheMonths is declared in the Enum, and Exclusives is built in the validation method.
When I pass 1 or 2 (Unassigned or Unknown) to this method, it correctly identifies them as valid - Exclusives, but not members of JustTheMonths.
But when I pass 4 to this code, it correctly identifies it as a member of the whole set, but incorrectly identifies it as a member of sub-group JustTheMonths.
What am I doing wrong here? Why does my code think that 4 is a member of (8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8172 | 16344) ?
private void Form1_Load(object sender, EventArgs e)
{
FloweringMonth test = FloweringMonth.NotApplicable;
if (IsValidFloweringMonthValue((int)test))
{
System.Diagnostics.Debug.WriteLine("Valid");
}
else
{
System.Diagnostics.Debug.WriteLine("Not Valid");
}
}
[Flags]
public enum FloweringMonth
{
Unassigned = 1, Unknown = 2, NotApplicable = 4,
Jan = 8, Feb = 16, Mar = 32, Apr = 64, May = 128, Jun = 256,
Jul = 512, Aug = 1024, Sep = 2048, Oct = 4086, Nov = 8172, Dec = 16344,
JustMonths = (Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec)
}
public static bool IsValidFloweringMonthValue(int value)
{
FloweringMonth incoming = (FloweringMonth)value;
FloweringMonth AllVals = FloweringMonth.Unassigned | FloweringMonth.Unknown |
FloweringMonth.NotApplicable | FloweringMonth.Jan | FloweringMonth.Feb |
FloweringMonth.Mar | FloweringMonth.Apr | FloweringMonth.May |
FloweringMonth.Jun | FloweringMonth.Jul | FloweringMonth.Aug |
FloweringMonth.Sep | FloweringMonth.Oct | FloweringMonth.Nov | FloweringMonth.Dec;
// does the incoming value contain any enum values from AllVals?
bool HasMembersOfAll = AllVals.HasFlag(incoming);
if (!HasMembersOfAll) return false;
// does the incoming value contain any enum values from JustTheMonths?
bool HasMembersOfMonths = FloweringMonth.JustMonths.HasFlag(incoming);
// does it contain any enum values from the set of three exclusive values?
FloweringMonth Exclusives = (FloweringMonth.Unassigned |
FloweringMonth.Unknown | FloweringMonth.NotApplicable);
bool HasMembersOfExclusives = Exclusives.HasFlag(incoming);
// an exclusive value cannot be mixed with any month values
if (HasMembersOfMonths && HasMembersOfExclusives) return false; // bad combo
// an exclusive value cannot be mixed with other exclusive values
if (incoming.HasFlag(FloweringMonth.Unassigned) &&
incoming.HasFlag(FloweringMonth.Unknown)) return false;
if (incoming.HasFlag(FloweringMonth.Unassigned) &&
incoming.HasFlag(FloweringMonth.NotApplicable)) return false;
if (incoming.HasFlag(FloweringMonth.Unknown) &&
incoming.HasFlag(FloweringMonth.NotApplicable)) return false;
return true;
}
Following #dukedukes answer, the problem was there your multiples of 2 were off.
One way to avoid this mistake is to use bitwise operations on the right-hand side.
[Flags]
enum Months
{
January = 1 << 3, // 8
February = 1 << 4, // 16
March = 1 << 5, // 32
}
Your multiples of 2 are incorrect. 4086 should be 4096, 8172 should be 8192, etc...
So... I have a a table like this:
RowID | DocID | Time | DepartmentID
1 | 1001 | 2015-11-20 | 1
2 | 1001 | 2015-11-21 | 2
3 | 1002 | 2015-11-20 | 1
4 | 1001 | 2015-11-25 | 1
5 | 1002 | 2015-11-22 | 3
6 | 1002 | 2015-11-30 | 1
My goal is to get the time in days a department spends with a document before sending it to another department.
I successfully achieved this by passing above table from SQL to a datatable in C#. Then get list of DocsID, and iterate throw each item in that list filtering the datatable with DocID and only then calculate the time between consecutive rows.
So the final result looks like:
DepartmentID | DocID | Time (Days)
1 | 1001 | 2
2 | 1001 | 5
1 | 1002 | 3
3 | 1002 | 9
The problem is this function in C# is taking about 30 seconds to get this results, so I'm looking for ways to improve it.
Is it possible to get this throw SQL only without making anything in C#?
My C# function (dt is a datatable with first table):
List<Int32> listDocIDs = new List<Int32>();
foreach (DataRow dr in dt.Rows)
{
int str = Convert.ToInt32(dr["DocID"].ToString());
if (!listDocIDs.Contains(str))
listDocIDs.Add(str);
}
DataTable times = new DataTable();
times.Columns.AddRange(new DataColumn[3] { new DataColumn("DepartmentID", typeof(Int32)),
new DataColumn("DocID",typeof(Int32)),
new DataColumn("Days",typeof(Int32)) });
foreach (int DocID in listDocIDs)
{
DataTable DocID_times = new DataTable();
using (SqlConnection conn = new SqlConnection(strCon))
{
conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter("getRecordsByDocID", conn);
adapter.SelectCommand.Parameters.Add("#DocID", SqlDbType.Int).Value = DocID;
adapter.SelectCommand.CommandType = CommandType.StoredProcedure;
adapter.Fill(DocID_times);
conn.Close();
}
int j = 0;
for (int i = 0; i < DocID_times.Rows.Count; i++)
{
j = i + 1;
if (i < (DocID_times.Rows.Count - 1))
{
DateTime tempo1 = DateTime.ParseExact(DocID_times.Rows[i]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture);
DateTime tempo2 = DateTime.ParseExact(DocID_times.Rows[j]["Time"].ToString(), "dd-MM-yyyy HH:mm:ss",
System.Globalization.CultureInfo.InvariantCulture);
double mins = (tempo2 - tempo1).TotalMinutes;
TimeSpan result = TimeSpan.FromMinutes(mins);
double days = result.TotalDays;
var rows = times.Select(string.Format("DepartmentID = {0} AND DocID = {1}", DepartmentID, DocID));
if (rows.Length == 0)
{
// Add your Row
times.Rows.Add(DepartmentID, DocID, days);
}
else
{
// Update your Days
rows[0]["days"] = Convert.ToInt32(rows[0]["days"].ToString()) + days;
}
}
}
}
If you're listing all the rows, I would calculate the days between records inside a while loop. It can be done purely with SQL, but it won't be as good as the while loop (which can have access to two rows at a time). To be able to do it purely in SQL, you would have to join the table with itself, joining each record with the next one.
IEnumerable<MySummarizedRow> GetSummarizedRows()
{
using (var entries = GetRowsOrderedByDocIdAndRowId().GetEnumerator())
{
if (entries.MoveNext())
{
var previous = entries.Current;
while (entries.MoveNext())
{
var current = entries.Current;
if (current.DocId == previous.DocId)
yield return new MySummarizedRow(previous.DepartmentId, current.DocId, current.Time.Substract(previous.Time).TotalDays + 1);
previous = current;
}
}
}
}
This function ignores the rows for a document that hasn't been passed to another department yet. You can easily change that yielding a new row with -1 days or something like that.
I have the below two tables
MBA
+--------+----------+------------+--------------+------------------+------------+
|mbaId | Channel | Product | ProgDate | ProgStartTime |ProgEndTime |
+--------+----------+ -----------+--------------+------------------+------------+
|12 | AA | SS | 01/04/2011 | 16:00:00 | 20:00:00 |
|13 | AA | SS | 01/04/2011 | 16:00:00 | 20:00:00 |
|14 | AA | SS | 01/04/2011 | 16:00:00 | 20:00:00 |
|15 | AA | SS | 01/04/2011 | 17:00:00 | 18:00:00 |
+--------+----------+------------+--------------+------------------+------------+
MAP
+----------+--------+---------------+-------------------+---------+----+
|mapId |Channel | Product |ProgDate | AdvTime| |
+----------+--------+---------------+-------------------+---------+----+
|8 | AA | SS | 01/04/2011 | 19:35:14| 30 |
|9 | AA | SS | 01/04/2011 | 18:40:19| 27 |
|10 | AA | SS | 01/04/2011 | 19:36:58| 35 |
|11 | AA | SS | 01/04/2011 | 17:47:13| 28 |
+----------+--------+---------------+-------------------+---------+----+
I would require the below output
+-----------+-------+-------+-------------+---------+--------------+-----------+-----+
| mapId |Channel|Product| ProgDate | AdvTime |ProgStartTime |ProgEndTime|mbaid|
+-----------+-------+-------+-------------+---------+--------------+-----------+-----+
| 8 | AA | SS | 01/04/2011 | 19:35:14|16:00:00 | 20:00:00 | 12 |
| 9 | AA | SS | 01/04/2011 | 18:40:19|16:00:00 | 20:00:00 | 13 |
| 10 | AA | SS | 01/04/2011 | 19:36:58|16:00:00 | 20:00:00 | 14 |
| 11 | AA | SS | 01/04/2011 | 17:47:13|16:00:00 | 17:00:00 | 15 |
+-----------+-------+-------+-------------+---------+--------------+-----------+-----+
I use the below code
select *
from MBA2 as mba
inner join Map2 as map on(map.Channel=mba.Channel and map.Product=mba.Product)
where(
(MBA.ProgStartTime < MBA.ProgEndTime
and MBA.ProgStartTime <=
case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
then dateadd(mi, 5, Map.AdvTime)
else Map.AdvTime
end
and MBA.ProgEndTime >=
case when datediff(mi, MBA.ProgStartTime, MBA.ProgEndTime) <= 60
then dateadd(mi, -5, Map.AdvTime)
else Map.AdvTime
end) or
(MBA.ProgStartTime > MBA.ProgEndTime
and (MBA.ProgStartTime <=
case when 1440 - datediff(mi, MBA.ProgEndTime, MBA.ProgStartTime) <= 60
then dateadd(mi, 5, Map.AdvTime)
else Map.AdvTime
end
or MBA.ProgEndTime >=
case when 1440 - datediff(mi, MBA.ProgEndTime, MBA.ProgStartTime) <= 60
then dateadd(mi, -5, Map.AdvTime)
else Map.AdvTime
end)))
order by advtime asc
But i get duplicates i.e the value 19:35:14 matches the range 16:00:00 to 20:00:00 for the ids 12,13 and 14. I need one value in MAP match one value in MBA.
SO i used the below code to add data into a dataset and find the duplicates in MAPID
if (repeatID.Contains(int.Parse(dr["mapID"].ToString())))
{
duplicateID.Add(int.Parse(dr["mapID"].ToString()));
}
else
{
DataRow dr1 = dt.NewRow();
dr1[0] = int.Parse(dr["mapID"].ToString());
dr1[10] = int.Parse(dr["mbaID"].ToString());
dr1[1] = (dr["Channel"].ToString());
dr1[2] = (dr["Product"].ToString());
dr1[3] = (dr["ProgDate"].ToString());
dr1[4] = (dr["AdvTime"].ToString());
dr1[5] = (dr["Progstarttime"].ToString());
dr1[6] = (dr["Progendtime"].ToString());
dr1[7] = (dr["Channel"].ToString());
dr1[8] = (dr["Product"].ToString());
dr1[9] = (dr["ProgDate"].ToString());
dt.Rows.Add(dr1);
}
repeatID.Add(int.Parse(dr["mapID"].ToString()));
i = i + 1;
}
sCon.Close();
}
And remove the repeating id row. Then use the below query to display the data without duplicates and again to datatable. It returns without duplicate mapid in datatable but with MBAID Dulicates.
using (SqlConnection sCon = new SqlConnection(connec))
{
foreach (int id in duplicateID)
{
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow ddr = dt.Rows[i];
if (ddr["mapID"].ToString() == id.ToString())
ddr.Delete();
}
sCon.Open();
{
SqlCommand cmd = new SqlCommand(#"select Distinct top 1 mp.Id as mapid, mb.Id as mbaid, mp.Channel, mp.Product, mp.ProgDate, mp.AdvTime, mb.Channel, mb.ProgStartTime,mb.ProgEndTime,mb.progdate, convert(time, dateadd(minute, datediff(minute, mb.progStartTime, mb.progEndTime), 0)) as timeDiff
from MBA22 as mb
inner join Map22 as mp on(mp.Channel=mb.Channel and mp.Product=mb.Product and mb.ProgDate=mp.ProgDate )
where(
(mb.ProgStartTime < mb.ProgEndTime
and mb.ProgStartTime <=
case when datediff(mi, mb.ProgStartTime, mb.ProgEndTime) <= 60
then dateadd(mi, 5, mp.AdvTime)
else mp.AdvTime
end
and mb.ProgEndTime >=
case when datediff(mi, mb.ProgStartTime, mb.ProgEndTime) <= 60
then dateadd(mi, -5, mp.AdvTime)
else mp.AdvTime
end) or
(mb.ProgStartTime > mb.ProgEndTime
and (mb.ProgStartTime <=
case when 1440 - datediff(mi, mb.ProgEndTime, mb.ProgStartTime) <= 60
then dateadd(mi, 5, mp.AdvTime)
else mp.AdvTime
end
or mb.ProgEndTime >=
case when 1440 - datediff(mi, mb.ProgEndTime, mb.ProgStartTime) <= 60
then dateadd(mi, -5, mp.AdvTime)
else mp.AdvTime
end)))
and mp.Id = '" + id + "' order by timeDiff asc", sCon);
cmd.CommandTimeout = 0;
SqlDataReader dr = cmd.ExecuteReader();
PLEASE HELPPPP
Try this query works accordingly but is risky as according to your need 1 record maps to another table so the sequence should be properly maintained else you will get wrong records
select
t2.mapId,
t1.Channel,
t1.Product,
t1.ProgDate,
t2.AdvTime,
t1.ProgStartTime,
t1.ProgEndTime,
t1.mbaid
FROM
(select
ROW_NUMBER() OVER(order by mbaid) as rId, *
from
mba
) t1,
(select
ROW_NUMBER() OVER(order by mapid) as rId, *
from
map
) t2
WHERE
t1.rId = t2.rId;a
FIDDLE
ROWNUMBER
here is an example
if 8.30 is there it should be 8 hours 30 minute
if 8 hour 20 minutes then 8.20
Please tell whether it is possible ? if yes
how ?
When people talk about decimal hours, they usually mean 0.1 = 6 minutes.
So, the correct formula to convert 8.3 would be:
8 hours + 3 * 6 minutes = 8:18
To convert 8:20 to decimal it would be:
8 + 20/6 = 8.333333 (probably round to 8.3)
If it always be separated with . and you want it for displaying then simply use this:
var ar="8.30".split(new[]{'.'});
Console.Write("{0} hours {1} minutes",ar[0], ar[1]);
PS: Here we are sure to have two elements in array, but please check length of array ar before using ar[1]
My approach would look something like this. (This is ruby so you'll have to convert it yourself but the logic is whats important here)
def zeropad(number)
return ((number.to_f < 10) ? "0" : "") + number.round.to_s
end
def decimal_to_time(value)
t = value.split(".") #returns an array of ["hour", "minutes"]
hours, minutes = t[0], t[1]
minutes = zeropad( (minutes.to_f / 10**minutes.length) * 60 ) # parse the minutes into a time value
return (minutes.to_i == 0) ? hours : hours + ":" + minutes
end
def findTime(value)
value =~ /^\d+\.\d+/ ? decimal_to_time(value) : value
end
Where findTime("5.015") gives you the appropriate time value.
I've tested this across the following tests and they all pass.
| entered_time | expected_results|
| "5.6" | "5:36" |
| "5.9" | "5:54" |
| "5.09" | "5:05" |
| "5.0" | "5" |
| "5.00" | "5" |
| "5.015" | "5:01" |
| "6.03" | "6:02" |
| "5.30" | "5:18" |
| "4.2" | "4:12" |
| "8.3" | "8:18" |
| "8.33" | "8:20" |
| "105.5" | "105:30" |
| "16.7" | "16:42" |
| "Abc" | "Abc" |
| "5:36" | "5:36" |
| "5:44" | "5:44" |
Here's a couple of extension methods (for DateTime and Decimal) that do the job:
public static class DecimalToTimeConverters
{
public static DateTime ToDateTime(this decimal value)
{
string[] parts = value.ToString().Split(new char[] { '.' });
int hours = Convert.ToInt32(parts[0]);
int minutes = Convert.ToInt32(parts[1]);
if ((hours > 23) || (hours < 0))
{
throw new ArgumentOutOfRangeException("value", "decimal value must be no greater than 23.59 and no less than 0");
}
if ((minutes > 59) || (minutes < 0))
{
throw new ArgumentOutOfRangeException("value", "decimal value must be no greater than 23.59 and no less than 0");
}
DateTime d = new DateTime(1, 1, 1, hours, minutes, 0);
return d;
}
public static Decimal ToDecimal(this DateTime datetime)
{
Decimal d = new decimal();
d = datetime.Hour;
d = d + Convert.ToDecimal((datetime.Minute * 0.01));
return d;
}
}
I tested this very quickly in an ASP.net webpage (I had a web project open at the time) using the following in a new blank page, and it seemed to work a treat:
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Decimal d = new decimal();
d = 3.45M;
Response.Write(d.ToDateTime().ToString());
Response.Write("<br />");
DateTime d2 = new DateTime(2009, 1, 1, 4, 55, 0);
Response.Write(d2.ToDecimal().ToString());
}
As per Rob but substitute
string[] parts = value.ToString().Split(new char[] { '.' });
int hours = Convert.ToInt32(parts[0]);
int minutes = Convert.ToInt32(parts[1]);
as
int hours = (int)value;
int minutes = (int)((value - minutes) * 100);
no strings or reliance on current culture (the assumption that the '.' is the decimal point)
How can I parse the txtDuration.Text Value into a decimal value?
if (txtDuration.Text)
{
var duration = int.Parse(txtDuration.Text);
var timespan = Boolean.Parse(hdfToggleDuration.Value) ? new TimeSpan (0, 0, duration, 0) : new TimeSpan (0, duration, 0, 0);
DateTime end = start.Add(timespan);
}