Problem with Math.Truncate, getting a double into an Integer - c#

First of all you should now im new in Programming, and english is not my mother language, im from germany.
I`m trying to write a programm, which says me how many Days, Hours and Minutes have passed, concluding to the user input. For the User input i have the double variable (time) and the integer (day), in this example i typed in 14.40 (its like 2.40pm, in germany we write it 14.40) and 2 (for tuesday).
Now i want to programm to Write the following sentence:
"Since Monday 1 Day, 14 Hours and 40 minutes have passed!"
Insted of that he prints out "Since Monday 1 Day, 1440 Hours and 0 minutes have passed!"
To split the double i used Math.Truncate to get the full hours (14), and then i subtract that from the the user input (14.40), to get the Minutes (40).
I can't find a solution in the Internet for that Problem, i hope you guys can help me with that.
class Program
{
static void Main(string[] args)
{
int day;
double time;
int VDays;
double VHours;
double VMinutes;
Console.Write("Which day do we have? (1=Monday, 2=Tuesday, ...):\n");
day = Convert.ToInt32(Console.ReadLine());
Console.Write("Which time is it?\n");
time = Convert.ToDouble(Console.ReadLine());
VDays = day - 1;
VHours = Math.Truncate(time);
VMinutes = time - VHours;
Console.WriteLine("Since Monday" + VDays + " Day, " + VHours + " Hours and " + VMinutes + " minutes have passed!");
Console.ReadLine();
}
}

Having tested it I can confirm this is a locale issue as Klaus Gütter mentioned.
Since Convert.ToDouble uses your German locale settings and commas are the decimal separators in German, it ignores the dot and interprets 14.40 as 1440.
You can recreate the problem with:
time = Convert.ToDouble(Console.ReadLine(), CultureInfo.GetCultureInfo("de-DE").NumberFormat);.
You can specify the locale to be used to fix the problem, here with InvariantCulture:
time = Convert.ToDouble(Console.ReadLine(), CultureInfo.InvariantCulture);
You also need to multiply VMinutes by 100 for it to work, since substracting the integer value from the time will leave you with a number between 0 and 1 (i.e 14.40 - 14 = 0.40, 0.40 * 100 = 40 minutes have passed).

Related

Having problem to convert Vb method into C# method

I wont to convert this VB method below into c# method. This method should calculate number of days for Rent and then multiply that number with txtRate textbox, so I can get the final number (txtTotal) which can be after stored into data grid view.
VB Method
Sub GetTotal()
Try
Dim day As Integer
day = DateDiff("d", Now.Date.ToString("MM-dd-yyyy"), DateTimePicker1.Value.ToString("MM-dd-yyyy"))
day += 1
lblDay.Text = day
txtTotal.Text = Format(day * CDbl(txtRate.Text), "#,##0.00")
Catch ex As Exception
txtTotal.Text = "0.00"
End Try
End Sub
I did not find any similar method like vb DateDiff is and that is the main problem.
You can just subtract one DateTime from another. It realizes a TimeSpan, which has a TotalDays property:
//if the date time picker date is in the future
(dateTimePicker1.Value - DateTime.Now).TotalDays
TotalDays is a decimal number, like 1.5. One thing to note with a lot of DateDiff functions (SQLServer, VBA, and maybe hence also VB - I can't quite remember) is that they give you the number of times the interval has changed between the dates which is subtly different to a time span
For example asking SQLServer's DateDiff for the years between 2020-12-31 23:59:59 and 2021-01-01 00:00:01 will say "1 year" because the year rocker up from 2020 to 2021, even though only 2 seconds have passed between the two dates
As such if you do specifically need that "imprecise" behavior, you might want to carefully assess whether a TineSpan route (which is very accurate and would give a TotalDays of eg 0.0000235 for the 2 seconds example a live whereas DateDiff would have said 1)
I managed to solve firs part of the problem. My current solution is this :
private void GetTotal()
{
try
{
DateTime d1 = DateTime.Now;
DateTime d2 = dtReturn.Value;
TimeSpan diff = d2.Subtract(d1);
lblDay.Text = diff.Days.ToString("0.00"); //here I get number of Rent days
}
catch (Exception)
{
txtTotal.Text = "0.00";
}
}
Now I need to multiply Value from lblDay with another txt fild (txtRate) so I can get a Total Value wich is stored into txtTotal Field. After I need to store transaction into data grid view

How to format an int/double to readable time value

I have a program that suggests the time of day to leave to go hunting duck/goose hunting on time. It asks the users for the time of sunrise, how long the drive will take, etc and calculates what time you should leave to make it there on time. My program works but I need to format the results. Example: Sunrise of 7, drive of 30, setup of 30, walking of 30, waiting of 30 results as 4.5 (which is correct) but I want it to read as 4:30. Any Suggestions?? Please and thanks!
Console.WriteLine("Enter sunrise");//7AM would be 420minutes
double sunrise = Convert.ToInt32(Console.ReadLine());
double minutes = sunrise * 60;
double legal = 30;//allowed to shoot 30min before sunrise
Console.WriteLine("How many minutes will it take to drive to" +
"your destination: ");
double drive = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("How many minutes will it take to set up: ");
double setup = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("How many minutes will it take to walk from " +
"your vehicle to the actual hunting spot:");
double walking = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Amount of time between setting up and " +
"pulling the trigger:");
double waiting = Convert.ToInt32(Console.ReadLine());
double departure = ((minutes - (legal + drive + setup + walking
+ waiting))/60);//6.5
Console.WriteLine("If sunrise is at " + sunrise +"AM, and it
takes " + drive + " minutes to drive there you should leave at" +
departure + "AM");
Change your
double ... = Convert.ToInt32(Console.ReadLine());
To
TimeSpan ... = TimeSpan.FromMinutes(int.Parse(Console.ReadLine());
And then use:
TimeSpan departure = sunrise - (legal + drive + setup + waiting);
Console.WriteLine("If sunrise is at {0}AM, and it takes {1} minutes to drive there you should leave at {2}AM",
sunrise, drive.Minutes, departure);
You can then play with TimeSpan formatting until you get the desired output.
One way to do it would be to get the sunrise time as a Time format (hh:mm) from the user, and the other values as minutes. Then you can convert sunrise to a DateTime, subtract 30 minutes, and subtract the total of the rest of the times. This will leave you with a DateTime result, which is easy to format with AM/PM information.
To assist in getting valid input from the user, I would create the following two methods, which get a TimeSpan and an int from the user (along with necessary retries if they input incorrect data). Note that the one that gets a TimeSpan only expects the hours and minutes, and automatically adds :00 for the seconds:
private static TimeSpan GetTimeFromUser(string prompt)
{
Console.Write(prompt);
TimeSpan result;
while (!TimeSpan.TryParse(Console.ReadLine() + ":00", out result))
{
Console.WriteLine("Please use format hh:mm for the time.");
Console.Write(prompt);
}
return result;
}
private static int GetIntFromUser(string prompt)
{
Console.Write(prompt);
int result;
while (!int.TryParse(Console.ReadLine(), out result))
{
Console.WriteLine("Please enter a valid integer.");
Console.Write(prompt);
}
return result;
}
With those helper functions out of the way, we can get the info from the user pretty easily, and then display back the results:
private static void Main()
{
DateTime sunrise = DateTime.Today.Add(GetTimeFromUser("Enter sunrise time: "));
DateTime legalStartTime = sunrise.AddMinutes(-30);
int driveTime = GetIntFromUser(
"How many minutes will it take to drive to your destination: ");
int setupTime = GetIntFromUser(
"How many minutes will it take to set up: ");
int walkTime = GetIntFromUser(
"How many minutes will it take to walk from your vehicle to the hunting spot: ");
int waitTime = GetIntFromUser(
"Number of minutes between setting up and pulling the trigger: ");
int totalTime = driveTime + setupTime + walkTime + waitTime;
DateTime departureTime = legalStartTime.AddMinutes(-totalTime);
Console.WriteLine($"If sunrise is at {sunrise:hh:mm tt}, and it takes {totalTime} " +
$"minutes to drive and get ready, you should leave at: {departureTime:hh:mm tt}");
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output
DateTime.Today.AddHours(departure).ToLongTimeString()
Although few solutions were introduced, i felt the need to add more complete but naive solution, which will handle sunrise as DateTime and represent result as time.
Console.WriteLine("Sunrise at:");
var sunrise = DateTime.Parse(Console.ReadLine());
Console.WriteLine("How many minutes will it take to drive to your destination: ");
var drive = TimeSpan.FromMinutes(int.Parse(Console.ReadLine()));
Console.WriteLine("How many minutes will it take to set up: ");
var setup = TimeSpan.FromMinutes(int.Parse(Console.ReadLine()));
Console.WriteLine("How many minutes will it take to walk from your vehicle to the actual hunting spot:");
var walking = TimeSpan.FromMinutes(int.Parse(Console.ReadLine()));
Console.WriteLine("Amount of time between setting up and pulling the trigger:");
var waiting = TimeSpan.FromMinutes(int.Parse(Console.ReadLine()));
var legalTimeBeforeSunriseInMin = TimeSpan.FromMinutes(30);
var calculatedDelta = (legalTimeBeforeSunriseInMin + drive + setup + walking + waiting);
var departure = sunrise.Add(-calculatedDelta).ToLongTimeString();
Console.WriteLine($"If sunrise is at {sunrise.ToLongTimeString()}, and it takes {drive} minutes to drive there you should leave at {departure}");
double t = 4.5;
TimeSpan s = TimeSpan.FromMinutes(t * 60);
string result = s.ToString(#"h\:mm");
If you have a time in fractional hours like
var departTimeInHours = 4.5;
And you want to display it as a 12-hour time formatted string with colon and AM/PM, one possibility is to create a DateTime from the fractional hours and use that type's built-in string conversion, which has the advantage of being localized (are there non AM/PM localized time formats?). The simplest way to convert the fractional hours to a DateTime is to convert them to ticks (which are 100 nanosecond units) and then call the constructor.
var strDepartTime = (new DateTime((long)(departTimeInHours*60*60*10000000)).ToString("t");

C# TimeSpan calculating hours

I am trying to create a time card solution in C# and having an issue with totaling hours worked for a week. From a drop down, the user would select the number of hours they worked in a day (ex. 5:30 - the 5:30 is the total hours worked, not the actual time 5:30). The user would select the hours each work day and the application would then total the hours for the week. The application I have written totals the hours, but I have two issues: if I use .Hours to add the hours up, I run into an issue when the total goes over 24; when I use .TotalHours, it calculates over 24 ok, but somehow it adds an hour randomly when I select :30 increments. Here is the code I have to calculate and display the totals:
using .Hours does not allow the total number of hours to go over 24. Instead it converts the 24 to 1 day and starts the adding the hours again, losing the original 24:
lblWorkgroupOneTotalTime.Text = (totalWeekOneHours.Hours).ToString("00") +
":" + (totalWeekOneHours.Minutes).ToString("00");
//using .TotalHours causes the calculation to randomly add an hour to the total:
lblWorkgroupTwoTotalTime.Text =
(totalWeekTwoHours.TotalHours).ToString("00").TrimStart('0') +
":" + (totalWeekTwoHours.Minutes).ToString("00");
I feel like I am very close to having everything work correctly, but I can't figure this part out.
How about this:
Initialize an example for 30 hours and 30 minutes:
TimeSpan totalWeekThreeHours = new TimeSpan(30, 30, 0);
(Timespan works better than DateTime here I feel.)
Then:
var hours = (int)totalWeekThreeHours.TotalMinutes / 60;
var mins = totalWeekThreeHours.TotalMinutes % 60;
Output:
var example1 = hours + ":" + mins;
var example2 = String.Format("{0} hours {1} mins", hours, mins);
Console.WriteLine("Example 1: " + example1);
Console.WriteLine("Example 2: " + example2);
//Output:
//Example 1: 30:30
//Example2: 30 hours 30 minutes
it adds an hour randomly
Nothing in programming happens "randomly". So when debugging, your first step should always be to look for patterns in your bug. As long as you believe the bug happens "randomly", you will have a mental block getting in the way of finding the bug.
As for your specific issue…
For any of the Total... properties of TimeSpan, this will be a double value that represents the entire time span in the units you're retrieving, including any fractional amounts.
For example, if the TimeSpan value represents 1 hour and 45 minutes, the TotalHours value will be 1.75. At the same time, you are telling the ToString() method that you want the value rounded to the nearest integer value. So, any time that the fractional part of your time span in hours is greater than one-half, the value is rounded up to the next hour value.
If you don't want that behavior, you should just truncate the value yourself before formatting it as a string:
lblWorkgroupTwoTotalTime.Text = string.Format("{0:0}:{1:00}",
(int)totalWeekTwoHours.TotalHours, totalWeekTwoHours.Minutes);
I also don't see why you used the format string "00" only to strip off the leading 0 after the fact. Easier to just not format the string that way in the first place.
Finally, note alternative syntax for formatting strings. Your approach (calling ToString() explicitly) is fine, but I find it wordy. The above is more concise, and does a better job separating the format from the input values.
The problem with displaying TotalHours with a format string of "00" is that it's going to round up. You have a couple of choices if you don't want to show days:
Use Hours + Days * 24 for the hours
Use TotalMinutes / 60 for hours
Convert TotalHours to an int, which will always round down
For example:
var totalHours = (totalWeekOneHours.Days * 24) + totalWeekOneHours.Hours;
// Or:
var totalHours = totalWeekOneHours.TotalMinutes / 60;
// Or:
var totalHours = (int)totalWeekOneHours.TotalHours;
Then you can output it:
lblWorkgroupOneTotalTime.Text = $"{totalHours:00}:{totalWeekOneHours.Minutes:00}";

Minute give wrong values on substract

I want to subtract minutes and get the difference. below is my code
double diff = currBlock.EndTime.Subtract(currBlock.StartTime).TotalMinutes;
In given code (currBlock.StartTime = 23:30:00) and (currBlock.EndTime= 00:20:00)
here starttime is time of today i.e.(09/26/2016 23:30:00), night time which will be consider as 11:30 PM and endtime is time of tomorrow i.e.(09/27/2016 00:20:00), morning time which will be consider as 12:20 Am. In my code i am getting values in minus which is -1390 and it is incorrect. So please help me to solve this.
Here i have attach image of data for further reference.
please explain me properly, how do i use it? it is just a time block for different shift so there is no date include in it
There is a date included in it. You're telling us that EndTime is something like 09/27/2016 00:20:00, while StartTime is something like 09/26/2016 23:30:00. The problem is that that knowledge is in your head and not in your code. If you subtract the values as TimeSpans, then you're literally saying: what is 30 minutes minus 23 hours and 30 minutes. The answer, of course is -23 hours. To get the real difference, you must include the dates, which means utilizing a DateTime or DateTimeOffset type for both StartTime and EndTime, so you can encode that whole date and time. Then, when you do the subtraction, it will return the right value.
Below Code works for me. Thanks friends for your support and help.
string strCurrDate = (DateTime.Now.Date + currBlock.EndTime).ToString();
DateTime dtYourDate = DateTime.Parse((DateTime.Now.AddDays(-1).Date + currBlock.StartTime).ToString());
string strYourDate = dtYourDate.ToShortDateString() + " " + dtYourDate.ToLongTimeString();
string strTotalMinsElapsed = TotalMinutesElapsed(dtYourDate).ToString();
private long TotalMinutesElapsed(DateTime dtYourDate)
{
long lTotalMinutesElapsed = 0;
//Find Current Date and Time
DateTime dtCurrent = DateTime.Now;
//Find Time Difference details between current date and your given date
TimeSpan tsDiff = dtCurrent.Subtract(dtYourDate);
//Add Total Minutes for Days difference
lTotalMinutesElapsed = lTotalMinutesElapsed + tsDiff.Days * (24 * 60);
//Add Total Minutes for Hour difference
lTotalMinutesElapsed = lTotalMinutesElapsed + tsDiff.Hours * 60;
//Add Minutes
lTotalMinutesElapsed = lTotalMinutesElapsed + tsDiff.Minutes;
return lTotalMinutesElapsed;
}

how to get the 12 hour date from DateTime

when i get the DateTime.Hour property, i always get the 24 hour time (so 6PM would give me 18).
how do i get the "12 hour" time so 6PM just gives me 6.
i obviously can do the check myself but i assume there is a built in function for this.
How about:
DateTime.Hour % 12
That will give 0-11 of course... do you want 1-12? If so:
((DateTime.Hour + 11) % 12) + 1
I don't think there's anything simpler built in...
DateTime.Now.ToString("hh"); --> Using this you will get "06" for 18h.
I don't know of any built in method, but you can always add an extension method to accomplish this.
Of course, you could always replace the code with the way you want to accomplish it.
public static class Extension
{
public static int GetTwelveCycleHour(this DateTime dateTime)
{
if (dateTime.Hour > 12)
{
return dateTime.Hour - 12;
}
return dateTime.Hour;
}
}
What about simply:
public static int GetTwelveCycleHour(this DateTime dateTime)
{
return Convert.ToInt32(dateTime.ToString("h"));
}
There's no built-in function, mainly because you shouldn't need it:
If you're doing this for output to the user, look at using a format string.
If you're doing this for a calculation, you can subtract datetimes or add timespans directly.
Outside of this, the math calculation is simple enough and already available in other answers here.
I thought the most convenient answer was submitted by Jon Skeet. The below is the same but converted to Visual Basic. I like things to be super easy. It took me a few to figure out the C# to Visual Basic Conversion. I included some 'extra' stuff as well. Hope this saves someone else time.
Visual Basic
(((DateTime.Now().Hour + 11) Mod 12) + 1)
Extra
Dim stringDate = DateTime.Now().Year &
DateTime.Now().Month.ToString("00") &
DateTime.Now().Day.ToString("00") & "_" &
(((DateTime.Now().Hour + 11) Mod 12) + 1).ToString("00") &
DateTime.Now().Minute.ToString("00")
The ToString("00") forces each Month/Day/Hour/Minute to always be represented by two digits.
Year = 2019
Month: April 4 = 04
Day: 3 = 03
Hour: 10 = 10
5 Minutes = 05
stringDate = 201904031005
DateTime date = Convert.ToDateTime("12/12/2022 20:20:00 PM");
var hour = date.Hour;
var dateTime = Convert.ToDateTime((date.ToShortDateString() + " " + hour + ":00:00"));
Console.WriteLine(dateTime); // 12/12/2022 8:00:00 PM
Console.WriteLine(hour); // 20

Categories