TimeSpan to Localized String in C# - c#

Is there an easy way (maybe built in solution) to convert TimeSpan to localized string? For example new TimeSpan(3, 5, 0); would be converted to 3 hours, 5minutes (just in polish language).
I can of course create my own extension:
public static string ConvertToReadable(this TimeSpan timeSpan) {
int hours = timeSpan.Hours;
int minutes = timeSpan.Minutes;
int days = timeSpan.Days;
if (days > 0) {
return days + " dni " + hours + " godzin " + minutes + " minut";
} else {
return hours + " godzin " + minutes + " minut";
}
}
But this gets complicated if i want to have proper grammar involved.

The easiest way to do this is to put the format string in a localized resource, and translate appropriately for each supported language.
Unfortunately there's no standard way to do such thing.
Nobody seems to agree in what should be the proper way.... :-\
And people like us that write software for multiple languages suffer.

I do not think this is possible. What you can do is something like this:
public static string ConvertToReadable(this TimeSpan timeSpan) {
return string.Format("{0} {1} {2} {3} {4} {5}",
timeSpan.Days, (timeSpan.Days > 1 || timeSpan.Days == 0) ? "days" : "day",
timeSpan.Hours, (timeSpan.Hours > 1 || timeSpan.Hours == 0) ? "hours" : "hour",
timeSpan.Minutes, (timeSpan.Minutes > 1 || timeSpan.Minutes == 0) ? "minutes" : "minute");
}

Here's the code that I've cooked out:
public static string ConvertToReadable(this TimeSpan timeSpan) {
int hours = timeSpan.Hours;
int minutes = timeSpan.Minutes;
int days = timeSpan.Days;
string hoursType;
string minutesType;
string daysType;
switch (minutes) {
case 1:
minutesType = "minuta";
break;
case 2:
case 3:
case 4:
minutesType = "minuty";
break;
default:
minutesType = "minut";
break;
}
switch (hours) {
case 1:
hoursType = "godzina";
break;
case 2:
case 3:
case 4:
hoursType = "godziny";
break;
default:
hoursType = "godzin";
break;
}
switch (days) {
case 1:
daysType = "dzieƄ";
break;
default:
daysType = "dni";
break;
}
if (days > 0) {
return days + " " + daysType + " " + hours + " " + hoursType + " " + minutes + " " + minutesType;
}
return hours + " " + hoursType + " " + minutes + " " + minutesType;
}

Related

I'm curious about the logic that checks only once at a certain time

I would like help.
There are some problems with the code.
I want to do only one inspection at a certain time every day.
In particular, the problem is the most serious in DateTime.Now.Hour == 11 part.
I am having difficulty checking certain times. I need to write code that can be checked only once at 11:00 in the whlie statement.
I created a license file and checked the date of the file.
public static CResult Dailytime(string date)
{
CResult result = new CResult();
if(result.nRet == 0)
{
while (true)
{
if (result.nRet == 1 || result.nRet == 2)
{
return result;
}
if (DateTime.Now.Hour == 11)
{
result = DailyCheckData(date);
if(result.nRet == 1 || result.nRet == 2)
{
return result;
}
}
System.Threading.Thread.Sleep(60 * 30 * 1000);
}
}
return result;
}
public static CResult DailyCheckData(string data)
{
CResult result = new CResult();
DateTime licenseDate = Convert.ToDateTime(data);
string dateNow = DateTime.Now.ToString("yyyy-MM-dd");
int compareDate = DateTime.Compare(Convert.ToDateTime(data), DateTime.Now);
if (licenseDate.ToString("yyyy-MM-dd") == dateNow)
{
result = ExpirationCertificate();
Console.WriteLine("Result = " + result.Result + " Msg = " + result.Msg + " nRet = " + result.nRet);
return result;
}
else
{
if (compareDate > 0)
{
result = TrueCertificate();
Console.WriteLine("Result = " + result.Result + " Msg = " + result.Msg + " nRet = " + result.nRet);
}
else if (compareDate <= 0)
{
result = ExpirationCertificate();
Console.WriteLine("Result = " + result.Result + " Msg = " + result.Msg + " nRet = " + result.nRet);
}
return result;
}
}
CResult class
nRet= 0 or 1 or 2
0 = fasle date
1 = false file
2 = true
Suggest or suggest ways to improve.
Can you try create a variable for DateTime.Now, after a line of code that value change.
DateTime licenseDate = Convert.ToDateTime(data);
string dateNow = DateTime.Now.ToString("yyyy-MM-dd");
int compareDate = DateTime.Compare(Convert.ToDateTime(data), DateTime.Now);
To
DateTime licenseDate = Convert.ToDateTime(data);
var now = DateTime.Now;
string dateNow = now.ToString("yyyy-MM-dd");
int compareDate = DateTime.Compare(licenseDate, now);
you shouldn't use Thread.Sleep() method for such a long duration. It is poor programming logic to make the thread sleep for such a long period.
What you can do to solve this is, is to make a Timer. There's an example attached in the link. A simple snippet to match your logic would be:
licenseStart = //setYours
lastCheck = DateTime.Now;
nextCheck = now.AddDays(1); // now.AddHours(1)
var timer = new Timer(o=>{/* Do work*/}, null, TimeSpan.Zero, nextCheck);
Hope it helps!
I asked about logic that can only loop once at 11 o'clock.
But I could not find the right answer and I found the answer.
I do not speak English well.
That's why others do not understand the intent of the question.
bool bOnce = true;
//bool s0nce = true;
while (true)
{
if (DateTime.Now.Hour == 11 && bOnce)
{
//run code
}
if (bOnce == true)
bOnce = false;
else
bOnce = true;
Thread.Sleep(10 * 60 * 1000);
}

C# Make a grocery list with a Switch Statement

whenever i run the program and select 7 it asks how many would you like which is really confusing, also I'm not sure if I'm adding the total items correctly. any help will be greatly appreciated.
namespace GoingShopping
{
class Program
{
private static int cabbageamount;
private static int tomatoamount;
private static int cheeseamount;
private static int breadamount;
private static int milkamount;
private static int onionamount;
bool isvalid = true;
static void Main(string[] args)
{
String cabbage = "1";
String tomatos = "2";
String Cheese = "3";
String bread = "4";
String milk = "5";
String onion = "6";
String done = "7";
String menu = "1) Cabbage" + System.Environment.NewLine +
"2) Tomatos" + System.Environment.NewLine +
"3) Cheese" + System.Environment.NewLine +
"4) Bread" + System.Environment.NewLine +
"5) Milk" + System.Environment.NewLine +
"6) Onion" + System.Environment.NewLine +
"7) I'm done shopping";
int total = cabbageamount + tomatoamount + cheeseamount + breadamount + milkamount + onionamount;
Console.Write("What you like to purchase ? " + System.Environment.NewLine);
Console.WriteLine(menu);
string wishlist = Console.ReadLine();
while (wishlist != "7")
{
switch (wishlist)
{
case "1":
Console.WriteLine("How many would you like ? ");
string cabbageinput = Console.ReadLine();
//int cabbageinput = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(menu);
break;
case "2":
Console.WriteLine("How many would you like ? ");
string tomatoinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "3":
Console.WriteLine("How many would you like ? ");
string cheeseinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "4":
Console.WriteLine("How many would you like ? ");
string breadinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "5":
Console.WriteLine("How many would you like ? ");
string milkinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "6":
Console.WriteLine("How many would you like ? ");
string onioninput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "7":
Console.WriteLine("You have chosen to buy : " + System.Environment.NewLine);
Console.WriteLine(cabbageamount + "X" + "Cabbages" + System.Environment.NewLine,
tomatoamount + "X" + "Tomatos" + System.Environment.NewLine,
cheeseamount + "X" + "Cheese" + System.Environment.NewLine,
breadamount + "X" + "Bread" + System.Environment.NewLine,
milkamount + "X" + "Milk" + System.Environment.NewLine,
onionamount + "X" + "Onions" + System.Environment.NewLine);
Console.WriteLine("Giving a total of" + total + "items");
break;
default:
break;
}
Console.ReadLine();
}
}
}
}
As Daniel above said you need to set the wishlist variable again
so instead of
Console.ReadLine();
put
wishlist = Console.ReadLine();
at the end of the while loop.
You never set wishlist again, your last "Console.ReadLine()" throws away the result, so wishlist is always the same value.
However, as #Steve points out, you'd be better off taking a different approach completely.
As a general hint, you should use the debugger to "watch" what the values are as the program executes - then you'd notice that wishlist is the same value.
You need to set wishlist to the value you have read. Also, you need to do that before your switch:
namespace GoingShopping
{
class Program
{
private static int cabbageamount;
private static int tomatoamount;
private static int cheeseamount;
private static int breadamount;
private static int milkamount;
private static int onionamount;
bool isvalid = true;
static void Main(string[] args)
{
String cabbage = "1";
String tomatos = "2";
String Cheese = "3";
String bread = "4";
String milk = "5";
String onion = "6";
String done = "7";
String menu = "1) Cabbage" + System.Environment.NewLine +
"2) Tomatos" + System.Environment.NewLine +
"3) Cheese" + System.Environment.NewLine +
"4) Bread" + System.Environment.NewLine +
"5) Milk" + System.Environment.NewLine +
"6) Onion" + System.Environment.NewLine +
"7) I'm done shopping";
int total = cabbageamount + tomatoamount + cheeseamount + breadamount + milkamount + onionamount;
Console.Write("What you like to purchase ? " + System.Environment.NewLine);
Console.WriteLine(menu);
string wishlist = "0";
while (wishlist != "7")
{
wishlist = Console.ReadLine().Trim();
switch (wishlist)
{
case "1":
Console.WriteLine("How many would you like ? ");
string cabbageinput = Console.ReadLine();
//int cabbageinput = Convert.ToInt32(Console.ReadLine());
Console.WriteLine(menu);
break;
case "2":
Console.WriteLine("How many would you like ? ");
string tomatoinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "3":
Console.WriteLine("How many would you like ? ");
string cheeseinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "4":
Console.WriteLine("How many would you like ? ");
string breadinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "5":
Console.WriteLine("How many would you like ? ");
string milkinput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "6":
Console.WriteLine("How many would you like ? ");
string onioninput = Console.ReadLine();
Console.WriteLine(menu);
break;
case "7":
Console.WriteLine("You have chosen to buy : " + System.Environment.NewLine);
Console.WriteLine(cabbageamount + "X" + "Cabbages" + System.Environment.NewLine,
tomatoamount + "X" + "Tomatos" + System.Environment.NewLine,
cheeseamount + "X" + "Cheese" + System.Environment.NewLine,
breadamount + "X" + "Bread" + System.Environment.NewLine,
milkamount + "X" + "Milk" + System.Environment.NewLine,
onionamount + "X" + "Onions" + System.Environment.NewLine);
Console.WriteLine("Giving a total of" + total + "items");
break;
default:
break;
}
}
}
}
}
Your whole logic for the switch statement is wrong. You should not use string inside your switch statements. I would suggest you to change these into char :
char charcabbage = '1'; // or 0x31
char tomatos = '2'; // or 0x32
char Cheese = '3'; // or 0x33
char bread = '4'; // or 0x34
char milk = '5'; // or 0x35
char onion = '6'; // or 0x36
char done = '7'; // or 0x37
Then you should make some InputHandler to handle user input and then return your "action" :
char ChooseAction(string message)
{
Console.WriteLine(message);
string input = string.Empty;
while ( (input = Console.ReadLine()) != "exit")
{
char c = input.Trim()[0];
if ( c >= 0x31 && c <= 0x37)
return c;
Console.WriteLine("Wrong input. Try again...");
}
return 0x38;
}
Now this method awaits for "exit" if you would like to close it or something or for valid input "1"-"7".
And as you can see now user can input values from 0x31 to 0x37 and in your switch statement you're running the same code 6 times so ... optimize this in a bit and change
//private static int cabbageamount;
//private static int tomatoamount;
//private static int cheeseamount;
//private static int breadamount;
//private static int milkamount;
//private static int onionamount;
// to this :
private static System.Collections.Generic.Dictionary<char, int> _items;
And initialize this before your loop begins :
_items = new System.Collections.Generic.Dictionary<char, int>();
for(char i = '0'; i < '7'; i++) {
_items.Add(i, 0);
}
Proceeding to your "pre-loop" statements now you can do somehing like :
char action = ChooseAction("What you like to purchase ? " + System.Environment.NewLine + menu);
And then proceed with your while loop :
while (action >= 0x31 && action <= 0x37)
Then just insert your switch statement in this format :
case '7':
{
Console.WriteLine("You have chosen to buy : " + System.Environment.NewLine);
Console.WriteLine(_items[0x31] + "X" + "Cabbages" + System.Environment.NewLine,
_items[0x32] + "X" + "Tomatos" + System.Environment.NewLine,
_items[0x33] + "X" + "Cheese" + System.Environment.NewLine,
_items[0x34] + "X" + "Bread" + System.Environment.NewLine,
_items[0x35] + "X" + "Milk" + System.Environment.NewLine,
_items[0x36] + "X" + "Onions" + System.Environment.NewLine);
Console.WriteLine("Giving a total of" + total + "items");
// set list to completed:
action = 0x38;
}
break;
default :
{
Console.WriteLine("How many would you like ? ");
string input = Console.ReadLine();
int temp = 0;
if(int.TryParse(input, out temp)) {
_items[action] += temp;
}
action = ChooseAction(menu);
}
Now all your problems should be gone :)

How to refine this code, in terms of performance and readability?

My Desired output :
if the difference is less than a minute the result should be "Updated just now" and if the difference is than greater than a minute and less than an hour then the result should be "Updated X mintues ago"
Code:
string result = "";
if (difference.Days == 0)
{
if (difference.Hours == 0)
{
if (difference.Minutes == 0)
{
result = "Updated just now";
}
else
{
result = "Updated " + difference.Minutes.ToString() + " minutes ago";
}
}
else
{
result = "Updated " + difference.Hours.ToString() + " hours ago";
}
}
else
{
result = "Updated " + difference.Days.ToString() + " days ago";
}
string format = "Updated {0} {1} ago";
string result = "Updated just now";
// this test can be deleted
if(difference.TotalSeconds > 60)
{
if(difference.Days != 0)
result = string.Format(format, difference.Days, "days");
else if (difference.Hours != 0)
result = string.Format(format, difference.Hours, "Hours");
else if (difference.Minutes != 0)
result = string.Format(format, difference.Minutes, "Minutes");
}
so that the result is cleaner, replace "days" by difference.Days > 1 ? "Days" : "Day"
the purpose of the format string, is to avoid memory leak and to allow user change text format easily and for multilang
string result = "Updated ";
if (difference.Days != 0)
result += difference.Days.ToString() + " days ago";
else if (difference.Hours != 0)
result += difference.Hours.ToString() + " hours ago";
else if (difference.Minutes != 0)
result += difference.Minutes.ToString() + " minutes ago";
else
result += "just now";

Refactoring else if statement that returns current week from Wednesday

I am quite concerned about whether or not the code in CurrentRentWeek.cs is future-proof, is it good practice to have this many else if statements? If not, what would be the best way to refactor it?
MainWindow.Xaml.cs
public MainWindow()
{
InitializeComponent();
// Set current rent week
var datecheckObject = new CurrentRentWeek();
CurrentRentWeekTextBlock.Text = datecheckObject.DateCheck(CurrentRentWeekTextBlock.Text);
}
CurrentRentWeek.cs
public string DateCheck(string rentWeek)
{
if (_today.DayOfWeek == DayOfWeek.Monday)
{
_cRentWeekStart = _today.AddDays(-5);
_cRentWeekEnd = _today.AddDays(2);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Tuesday)
{
_cRentWeekStart = _today.AddDays(-6);
_cRentWeekEnd = _today.AddDays(1);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Wednesday)
{
_cRentWeekStart = _today.AddDays(0);
_cRentWeekEnd = _today.AddDays(7);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Thursday)
{
_cRentWeekStart = _today.AddDays(-1);
_cRentWeekEnd = _today.AddDays(6);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Friday)
{
_cRentWeekStart = _today.AddDays(-2);
_cRentWeekEnd = _today.AddDays(5);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Saturday)
{
_cRentWeekStart = _today.AddDays(-3);
_cRentWeekEnd = _today.AddDays(4);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else if (_today.DayOfWeek == DayOfWeek.Sunday)
{
_cRentWeekStart = _today.AddDays(-4);
_cRentWeekEnd = _today.AddDays(3);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +
_cRentWeekEnd.ToString("dd/MM/yyyy");
}
else
{
rentWeek = "";
}
return rentWeek;
}
You can start out with a generalized function to get the start of the week for any give date:
public static DateTime StartOfWeek(DateTime date)
{
while (date.DayOfWeek != DayOfWeek.Wednesday)
date = date.AddDays(-1);
return date;
}
Then you can simply call that method, add a fixed number of days to get to the end of the week, and create the string for those dates:
public string DateCheck()
{
var startOfWeek = StartOfWeek(_today);
var endOfWeek = startOfWeek.AddDays(7);
return string.Format("Current Rent Week: {0} - {1}",
startOfWeek.ToString("dd/MM/yyyy"),
endOfWeek.ToString("dd/MM/yyyy"));
}
You want that Wednesday is the beginning of the week? You can use this:
int daysDiff = (int)_today.DayOfWeek - (int)DayOfWeek.Wednesday;
if (daysDiff >= 0)
_cRentWeekStart = _today.AddDays(-daysDiff);
else
_cRentWeekStart = _today.AddDays(-(7 + daysDiff));
_cRentWeekEnd = _cRentWeekStart.AddDays(7);
This will return the last week's wednesday if today is "less" than wednesday which seems to be desired.
I think a switch statement would be much clearer for your case and give time savings but I doubt thats an issue.
switch (_today.DayOfWeek)
{
case DayOfWeek.Monday:
_cRentWeekStart = _today.AddDays(-5);
_cRentWeekEnd = _today.AddDays(2);
rentWeek = "Current Rent Week: " + _cRentWeekStart.ToString("dd/MM/yyyy") + " - " +_cRentWeekEnd.ToString("dd/MM/yyyy");
break;
case DayOfWeek.Tuesday:
//...
break;
//rest of cases
}

Time elapsed between two dates

I want to find the exact time elapsed between two dates with a condition that if any value is "0" its measurement units should disappear. for example if hours and minutes are o than the elapsed time should come like 1 day 40 seconds not like 1 day 0 hours 0 minutes 40 seconds.
TimeSpan elapsed = completdDate.Subtract(insertdDate);
int daysEl= elapsed.Days;
int hrsEl= elapsed.Hours;
int minsEl = elapsed.Minutes;
int secEl = elapsed.Seconds;
string totalTime = string.Empty;
string days = string.Empty;
string hours = string.Empty;
string mins = string.Empty;
string secs = string.Empty;
if (daysEl == 0 )
days = days.Replace(daysEl.ToString() , "");
else
days = daysEl.ToString();
if (hrsEl==0)
hours = hours.Replace(hrsEl.ToString() , "");
else
hours = hrsEl.ToString();
if (minsEl == 0)
mins = mins.Replace(minsEl.ToString(), "");
else
mins = minsEl.ToString();
if (secEl == 0)
secs = secs.Replace(secEl.ToString(), "");
else
secs = secEl.ToString();
totalTime = days + "days"
+ hours + "hours"
+ mins + "minutes"
+ secs + "seconds";
********************************Output*****************************
You can get rid of the intermediate strings and if statements:
totalTime =
(daysEl == 0 ? "" : (daysEl + " days "))
+ (hoursEl == 0 ? "" : (hoursEl + " hours "))
+ (minsEl == 0 ? "" : (minsEl + " minutes "))
+ (secsEl == 0 ? "" : (secsEl + " seconds "));
If you want to omit zero values, you're more likely looking at a formatting issue, not a calculation one, and it might be easier to use a StringBuilder.
var sb = new StringBuilder();
if (elapsed.Days != 0)
sb.AppendFormat("{0} days ", elapsed.Days);
if (elapsed.Hours != 0)
sb.AppendFormat("{0} hours ", elapsed.Hours);
if (elapsed.Minutes != 0)
sb.AppendFormat("{0} minutes ", elapsed.Minutes);
if (elapsed.Seconds != 0)
sb.AppendFormat("{0} seconds ", elapsed.Seconds);
if (sb.Length == 0)
return "instant!";
// get rid of the last space in there!
return sb.ToString().Substring(0,sb.Length-1);
By using a format, you're able to more succinctly bind the value with the units (ie "14 seconds") and thus put the whole portion into an if statement, bypassing the section entirely if it's zero.
void Main()
{
TimeSpan elapsed = DateTime.Now - DateTime.Now.AddDays(-1);
int daysEl= elapsed.Days;
int hrsEl= elapsed.Hours;
int minsEl = elapsed.Minutes;
int secEl = elapsed.Seconds;
var sb = new StringBuilder();
if (daysEl != 0 )
sb.Append(daysEl + " days ");
if (hrsEl != 0)
sb.Append(hrsEl + " hours ");
if (minsEl != 0)
sb.Append(minsEl + " mins ");
if (secEl != 0)
sb.Append(secEl + " secs ");
string totalTime = sb.ToString();
Console.WriteLine (totalTime);
}

Categories