I have been trying to make a simple second to hour and minute converter just to practice some C#. The weird thing is as I pass 599 seconds mark, the program subtracts 60 seconds. So, 540 seconds equals 9 minutes; 599 seconds equals 9 minutes 59 seconds, but 600 seconds equals to 9 minutes. I tried using a button to trigger the commands instead of textchanged and button did the job fine. So, I reckon, the root of the problem must be textchanged event itself. I'll be adding three examples. Screenshot images are in Turkish but you will easily get the idea.
How can I solve this, and what causes this problem? This is really mind boggling.
Screenshot
int second, minute, hour, minuteLeft, secondLeft;
private void txtTime_TextChanged(object sender, EventArgs e)
{
CalculateTime();
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
void CalculateTime()
{
if (txtTime.Text != "")
{
second = Convert.ToInt32(txtSure.Text);
secondLeft = second % 60;
second = second - minuteLeft;
minute = second / 60;
minuteLeft = minute % 60;
minute = minute - minuteLeft;
hour = minute / 60;
lblMsg.Text = hour.ToString() + " hours, " + minuteLeft.ToString() + " minutes " + secondLeft.ToString() + " seconds.";
}
else
{
lblMsg.Text = "";
}
You are subtracting minuteLeft from the number of seconds:
second = second - minuteLeft;
That should be subtracting the secondLeft value:
second = second - secondLeft;
You could consider attacking the problem in a different way:
var durationInSeconds = Convert.ToInt32(txtTime.Text);
var duration = new TimeSpan(0, 0, durationInSeconds);
var second = duration.Seconds;
var minute = duration.Minutes;
var hour = Convert.ToInt32(Math.Truncate(duration.TotalHours));
TimeSpan is well suited to this class of problem, and will allow you to 'automatically' extract the hour, minute and second component of the duration.
You could also consider replacing:
hour.ToString() + " hours, " + minuteLeft.ToString() + " minutes " + secondLeft.ToString() + " seconds.";
with a call to:
public static string ToPrettyFormat(TimeSpan timeSpan)
{
var dayParts = new[] { GetDays(timeSpan), GetHours(timeSpan), GetMinutes(timeSpan) }
.Where(s => !string.IsNullOrEmpty(s))
.ToArray();
var numberOfParts = dayParts.Length;
string result;
if (numberOfParts < 2)
result = dayParts.FirstOrDefault() ?? string.Empty;
else
result = string.Join(", ", dayParts, 0, numberOfParts - 1) + " and " + dayParts[numberOfParts - 1];
return result.UppercaseFirst();
}
Stolen from https://codereview.stackexchange.com/questions/24995/convert-timespan-to-readable-text .
Related
First time when downloading the TimeDate.Now is for example 15:57 so I RoundDown make 15:55 format it and try to download it.
If no success in the completed event I'm trying to round it again from 15:55 to 15:50 formatting again and trying to download again.
The problem is that it's not rounding down again. In the completed event if there is error this line :
current = RoundDown(current, TimeSpan.FromMinutes(-5));
It's still the rounded 15:55 from the above and I want that until the download is not success keep round down and try to download the new currentLink with the new rounded down. 15:50 not success make it 15:45 not success 15:40 and so on round down and build the currentLink over and over again until the download is success.
public void GetImages()
{
defaultlink = "https://IMSRadar/IMSRadar_";
current = RoundDown(DateTime.Now, TimeSpan.FromMinutes(-5));
var ct = current.ToString("yyyyMMddHHmm");
currentLink = defaultlink + ct + ".gif";
using (System.Net.WebClient wc = new System.Net.WebClient())
{
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
wc.DownloadFileAsync(new Uri(currentLink), #"d:\test.gif");
}
}
private void Wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
if (e.Error != null)
{
using (System.Net.WebClient wc = new System.Net.WebClient())
{
current = RoundDown(current, TimeSpan.FromMinutes(-5));
var ct = current.ToString("yyyyMMddHHmm");
currentLink = defaultlink + ct + ".gif";
wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
wc.DownloadFileAsync(new Uri(currentLink), #"d:\test.gif");
}
}
else
{
GenerateRadarLinks();
}
}
The method RoundDown
DateTime RoundDown(DateTime date, TimeSpan interval)
{
return new DateTime(date.Ticks / interval.Ticks *
interval.Ticks);
}
Your roundDown won't work once you arrived at a date, which is already at some multiple of 5 minutes. Imagine the following:
Assuming integer division 103 / 5 * 5 will give 20 * 5 thus 100 as expected. But in the next iteration you then have 100 / 5 * 5 will again give 100, because
100 / 5 == 103 / 5 == 20 (with integer division).
So for this to work, you will need to decrement the time by at least one tick, so it's not a multiple of 5 minutes anymore.
DateTime RoundDown(DateTime date, TimeSpan interval) {
return new DateTime((date.Ticks - 1)/ interval.Ticks * interval.Ticks);
}
I personally would use the RoundDown method only once to generate the first timestamp that is a multiple of 5. For all following requests, I'd just take the current timestamp and decrement it by 5 minutes.
//inital timestamp
current = RoundDown(DateTime.Now, TimeSpan.FromMinutes(-5));
//in the error handler
current = current.AddMinutes(-5);
I would like to write a converter from milliseconds to the highest possible time value before reaching a 0,x value.
Let me clarify this with examples.
Let's assume you have 1500ms this should result in 1,5secs, because its the highest possible digit value not resulting in 0,x.
So different examples would be
10ms = 10,0ms
100ms = 100,0ms
1000ms = 1,0sec
10000ms = 10,0sec
100000ms = 1,6min
1000000ms = 16,0min
10000000ms = 2,7hours
(The method should more or less be endless, so from hours to days, to weeks, to months, to years, to decades and so on...)
Is there a .net method for this?
Something like the following
public static string ConversionMethod(UInt64 ms)
{
// change output format as needed
string format = "######.###";
var cutoffs = new List<UInt64>() {
1000, // second
60000, // minute
3600000, // hour
86400000, // day
604800000, // week = day * 7
2592000000, // month = day * 30
31536000000, // year = day * 365
315360000000, // decade = year * 10
3153600000000, // century = decade * 10 (100 years)
31536000000000, // millenia = century * 10 (1000 years)
31536000000000000 // megayear = year * 100000
// 18446744073709551615 // UInt64 MaxValue
// 31536000000000000000 // gigayear = year * 100000000
};
var postfix = new List<String>() {
"second",
"minute",
"hour",
"day",
"week",
"month",
"year",
"decade",
"century",
"millenia",
"megayear"
};
// The above are listed from smallest to largest for easy reading,
// but the comparisons need to be made from largest to
// smallest (in the loop below)
cutoffs.Reverse();
postfix.Reverse();
int count = 0;
foreach (var cutoff in cutoffs)
{
if (ms > cutoff)
{
return ((decimal)((decimal)ms / (decimal)cutoff)).ToString(format) + " " + postfix[count];
}
count++;
}
return ms + " ms";
}
Conversion for the fraction is a bit dirty, might want to clean that up. Also, you'll have to decide how you want to handle leap years (and leap seconds), etc.
While not the final solution, maybe TimeSpan can help you achieve what you are looking for.
It is to be noted however, TimeSpan supports only up to TotalDays.
var timespan = TimeSpan.FromMilliseconds(1500);
var seconds = timespan.TotalSeconds; // equals: 1.5
It seems the TimeSpan class is the closest thing that meets your need, but clearly it's not exactly what you want. My take on it would look something like this:
public static string ScientificNotationTimespan(int milliseconds)
{
var timeSpan = new TimeSpan(0, 0, 0, 0, milliseconds);
var totalDays = timeSpan.TotalDays;
if (totalDays < 7)
{
if (timeSpan.TotalDays > 1) return timeSpan.TotalDays.ToString() + " days";
if (timeSpan.TotalHours > 1) return timeSpan.TotalHours.ToString() + " hours";
if (timeSpan.TotalMinutes > 1) return timeSpan.TotalMinutes.ToString() + " minutes";
if (timeSpan.TotalSeconds > 1) return timeSpan.TotalSeconds.ToString() + " seconds";
return milliseconds.ToString() + "milliseconds";
}
var weeks = totalDays / 7;
//How long is a month? 28, 29, 30 or 31 days?
var years = totalDays / 365;
if (years < 1) return weeks.ToString() + " weeks";
var decades = years / 10;
if (decades < 1) return years.ToString() + " years";
var centuries = decades / 10;
if (centuries < 1) return decades.ToString() + " decades";
var millenia = centuries / 10;
if (millenia < 1) return centuries.ToString() + " centuries";
return millenia.ToString() + " millenia";
}
Here is solution for years, months using DateTime and Gregorian calendar (meaning leap years, calendar months). Then it uses the TimeSpan solution as already submitted.
static string ToMostNonZeroTime(long ms) {
const int hundretsNanosecondsInMillisecond = 10000;
long ticks = (long)ms * hundretsNanosecondsInMillisecond;
var dt = new DateTime(ticks);
if((dt.Year - 1) > 0) { // starts with 1
double daysToYear = (dt.DayOfYear - 1) * 1.0 / (DateTime.IsLeapYear(dt.Year) ? 366 : 365);
daysToYear += dt.Year - 1;
return $"{daysToYear:0.0} years";
}
if((dt.Month - 1) > 0) {
double daysToMonth = (dt.Day - 1) * 1.0 / DateTime.DaysInMonth(dt.Year, dt.Month);
daysToMonth += dt.Day - 1;
return $"{daysToMonth:0.0} months";
}
// can use TimeSpan then:
var ts = TimeSpan.FromMilliseconds(ms);
if(ts.TotalDays >= 1)
return $"{ts.TotalDays:0.0} days";
if(ts.TotalHours >= 1)
return $"{ts.TotalHours:0.0} hours";
if(ts.TotalMinutes >= 1)
return $"{ts.TotalMinutes:0.0} minutes";
if(ts.TotalSeconds >= 1)
return $"{ts.TotalSeconds:0.0} seconds";
return $"{ms} milliseconds";
}
It prints
100ms: 100 milliseconds
1000ms: 1.0 seconds
10000ms: 10.0 seconds
100000ms: 1.7 minutes
1000000ms: 16.7 minutes
10000000ms: 2.8 hours
100000000ms: 1.2 days
1000000000ms: 11.6 days
20000000000ms: 19.6 months
200000000000ms: 6.3 years
Have a look at https://ideone.com/QZHOM4
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
We've recently covered "if statements etc..." in my class and I'm having trouble with this question. (Apologies for my poor english)
This is the question:
Create an application that lets the user enter a number of seconds and works as follows:
There are 60 seconds in a minute. If the number of seconds entered by the user
is greater than or equal to 60, the program should display the number of minutes
in that many seconds.
There are 3,600 seconds in an hour. If the number of seconds entered by the
user is greater than or equal to 3,600, the program should display the number
of hours in that many seconds.
There are 86,400 seconds in a day. If the number of seconds entered by the user
is greater than or equal to 86,400, the program should display the number of
days in that many seconds.
And this is my answer full of mistakes:
private void button1_Click(object sender, EventArgs e)
{
//Declaring Variables
int totalSeconds;
int hours;
int minutes;
int minutesRemainder;
int hoursRemainderMinutes;
int hoursRemainderSeconds;
// Parsing and calculations
totalSeconds = int.Parse(textBox1.Text);
minutes = totalSeconds / 60;
minutesRemainder = totalSeconds % 60;
hours = minutes / 60;
hoursRemainderMinutes = minutes % 60;
hoursRemainderSeconds = hoursRemainderMinutes % 60;
if (totalSeconds >= 60)
{
MessageBox.Show(totalSeconds.ToString());
}
else if (totalSeconds >= 3600)
{
MessageBox.Show(minutes.ToString() + " minutes, " + minutesRemainder.ToString() + " seconds");
}
else if (totalSeconds >= 84600)
{
MessageBox.Show(hours.ToString() + " hours, " + hoursRemainderMinutes.ToString() + " minutes, " + hoursRemainderSeconds.ToString() + " seconds");
}
}
}
}
When run, my program doesn't calculate anything. What am I doing wrong?
You should use TimeSpan.FromSeconds method.
It will give you TimeSpan structure instance where you have access to:
TotalDays
TotalHours
TotalMinutes
properties.
Edit
They say in comments that you want to achieve that without using any libraries.
Then the approach would be (in terms of your taks):
int totalSeconds = ....;///
int totalMinutes = totalSeconds / 60;
int totalHours = totalMinutes / 60;
int totalDays = totalHours / 24;
if (totalDays > 0){
//show days
} else if (totalHours > 0){
//show hours
} else if (totalMinutes > 0){
//show minutes
} else {
//show seconds
}
Ok. Let's assume you don't want to use a TimeSpan. Your code is pretty close to be working. Your problem is that your last "else if" statement should be inversed with the if statement like this :
if (totalSeconds >= 86400)
{
Console.WriteLine(days.ToString() " days," + hours.ToString() + " hours, " + hoursRemainderMinutes.ToString() + " minutes, " + hoursRemainderSeconds.ToString() + " seconds");
}
else if (totalSeconds >= 3600)
{
Console.WriteLine(hours.ToString() + " hours, " + hoursRemainderMinutes.ToString() + " minutes, " + hoursRemainderSeconds.ToString() + " seconds");
}
else if (totalSeconds >= 60)
{
Console.WriteLine(minutes.ToString() + " minutes, " + minutesRemainder.ToString() + " seconds");
}
else
{
Console.WriteLine(totalSeconds.ToString());
}
That will do the trick.
TimeSpan is the easiest way to go.
int Input = 32453; //Amount of seconds
TimeSpan ts = new TimeSpan(0, 0, Input); //3 constructor arguments are (Hours, Minutes, Seconds)
if (ts.Days > 0)
{
Console.WriteLine(ts.Days + " Day(s)");
}
else if (ts.Hours > 0)
{
Console.WriteLine(ts.Hours + " Hour(s)");
}
else if (ts.Minutes > 0)
{
Console.WriteLine(ts.Minutes + " Minute(s)");
}
else
{
Console.WriteLine(ts.Seconds + " Second(s)");
}
Console.Read();
Here's how you can calculate all the values and determine which ones need to be in the output
int seconds = totalSeconds % 60;
int totalMinutes = totalSeconds / 60;
int minutes = totalMinutes % 60;
int totalHours = totalMinutes / 60;
int hours = totalHours % 24;
int totalDays = totalHours / 24;
if (totalDays > 0)
{
Console.Write(totalDays + " Days ");
}
if (totalHours > 0)
{
Console.Write(hours + " Hours ");
}
if (totalMinutes > 0)
{
Console.Write(minutes + " Minutes ");
}
Console.WriteLine(seconds + " Seconds");
Or using a StringBuilder so you can display it in the MessageBox
int seconds = totalSeconds % 60;
int totalMinutes = totalSeconds / 60;
int minutes = totalMinutes % 60;
int totalHours = totalMinutes / 60;
int hours = totalHours % 24;
int totalDays = totalHours / 24;
StringBuilder builder = new StringBuilder;
if (totalDays > 0)
{
builder.Append(totalDays + " Days ");
}
if (totalHours > 0)
{
builder.Append(hours + " Hours ");
}
if (totalMinutes > 0)
{
builder.Append(minutes + " Minutes ");
}
builder.Append(seconds + " Seconds");
MessageBox.Show(builder.ToString());
Ok, so this was my first question on StackOverflow, I see the comments haven't been great (and the post keeps getting deleted before I have had a chance to fix it). Give me a chance! My understanding was the question should be as direct as possible and not create 'discussions'?
This is what I have tried already, but the output is not what I expect
int secondsToHours(seconds) {
int totalSec = seconds;
int hrs = totalSec % 3600;
int secs = totalSec % 60;
int mins = totalSec / 60;
string result = hrs + ":" + mins + ":" + secs;
Console.WriteLine(result);
Console.ReadLine();
}
You can use TimeSpan struct:
TimeSpan ts = TimeSpan.FromSeconds(seconds);
And then build string you want:
ts.ToString(#"hh\:mm\:ss")
Look at the TimeSpan class
TimeSpan span = TimeSpan.FromSeconds(total seconds here);
Then look at the Days, Hours, Minutes and Seconds properties, or the TotalDays, TotalHours etc
Well, you could use a TimeSpan object
int seconds = 104700;
TimeSpan ts = new TimeSpan(0, 0, seconds);
Console.WriteLine("Days:" + ts.Days +
", Hours:" + ts.Hours +
", Minutes:" + ts.Minutes +
", Seconds:" + ts.Seconds );
You need to subtract from totalSec. For 4700 as example;
int left;
int hrs = totalSec / 3600; // hrs will be 1
left = totalSec - hrs * 3600; //left will be 1100
int mins = left / 60; //mins will be 18
left = left - mins * 60; // left will be 20
int secs = left; // secs will be 20
As a solution, 4700 will be 1 hours, 18 minutes and 20 seconds.
But using TimeSpan properties would be better such a case. You can use TimeSpan(Int32, Int32, Int32) constructor like;
TimeSpan ts = new TimeSpan(0, 0, seconds);
int hrs = ts.Hours; // 1
int mins = ts.Minutes; // 18
int secs = ts.Seconds; // 20
Simplest way would be using TimeSpan as already suggested in previous answer but also you could try this if you want to do it using Math:
private static void secondsToHours(int seconds)
{
int hrs = seconds / 3600;
int remainder = seconds % 3600;
int mins = remainder / 60;
int secs = seconds % 60;
string result = hrs + ":" + mins + ":" + secs;
Console.WriteLine(result);
Console.ReadLine();
}
I would like to calculate the remaining minutes to the "next" half an hour or hour.
Say i get a start time string of 07:15, i want it to calculate the remaining minutes to the nearest half an hour (07:30).
That would be 15min.
Then i can also have an instance where the start time can be 07:45 and i want it to calculate the remaining minutes to the nearest hour (08:00).
That would also be 15min.
So any string less then 30min in a hour would calculate to the nearest half an hour (..:30) and any string over 30min would calculate to the nearest hour (..:00).
I don't want to do a bunch of if statements, because i get from time strings that can start from and minute in an hour.
This is what i do not want to do:
if (int.Parse(fromTimeString.Right(2)) < 30)
{
//Do Calculation
}
else
{
//Do Calculation
}
public static string Right(this String stringValue, int noOfCharacters)
{
string result = null;
if (stringValue.Length >= noOfCharacters)
{
result = stringValue.Substring(stringValue.Length - noOfCharacters, noOfCharacters);
}
else
{
result = "";
}
return result;
}
Is there not an easier way with linq or with the DateTime class
Use modulo operator % with 30. Your result will be equal to (60 - currentMinutes) % 30. About LINQ its used for collections so i can't realy see how it can be used in your case.
You can use this DateTime tick-round approach to get the timespan until next half hour:
var minutes = 30;
var now = DateTime.Now;
var ticksMin = TimeSpan.FromMinutes(minutes).Ticks;
DateTime rounded = new DateTime(((now.Ticks + (ticksMin/2)) / ticksMin) * ticksMin);
var diff=rounded-now;
var minUntilNext = diff.TotalMinutes > 0 ? diff.TotalMinutes : minutes + diff.TotalMinutes;
var minutesToNextHalfHour = (60 - yourDateTimeVariable.Minutes) % 30;
This should do it:
int remainingMinutes = (current.Minute >= 30)
? 60 - current.Minute
: 30 - current.Minute;
var hhmm = fromTimeString.Split(':');
var mins = int.Parse(hhmm[1]);
var remainingMins = (60 - mins) % 30;
var str = "7:16";
var datetime = DateTime.ParseExact(str, "h:mm", new CultureInfo("en-US"));
var minutesPastHalfHour = datetime.Minute % 30;
var minutesBeforeHalfHour = 30 - minutesPastHalfHour;
I would use modulo + TimeSpan.TryParse:
public static int ComputeTime(string time)
{
TimeSpan ts;
if (TimeSpan.TryParse(time, out ts))
{
return (60 - ts.Minutes) % 30;
}
throw new ArgumentException("Time is not valid", "time");
}
private static void Main(string[] args)
{
string test1 = "7:27";
string test2 = "7:42";
Console.WriteLine(ComputeTime(test1));
Console.WriteLine(ComputeTime(test2));
Console.ReadLine();
}