C# setting format of text correctly in Excel - c#

I have a console app that creates several excel documents and everything works fine expect when I place a string called period which is Jan 19 into the cell A2.
Excel changes it to Jan-19 and when I try to change the format of the field using the code below nothing happens.
period = periodDescription.Substring(0, 3) + " 20" + year;
string numberFormat = "General";
xlWorksheet.Cells[2, 1].NumberFormat = numberFormat;
xlWorksheet.Cells[2, 1] = period;
What am i doing wrong?
Update:
Should add I have tried
string numberFormat = "";
string numberFormat = "MMM yyyy";

The General format will autodetect for dates and format them accordingly. I believe what you want to do is explicitly mark it a string by adding a single quote mark to the beginning of it.
Edit: It might be, depending on your final usage, more appropriate to change the formatting of the output to the "MMM dd". This would leave a date in the cell and format it for display the way you want.

The post here:
Changing excel format
Answer the question with:
string numberFormat = "#";

You can certainly do what you are seeking by using a raw text format (using #), but there may be advantages to treating the field as a date, in which case the format is definitely possible. For example, if you sort on this field as text, "Feb 19" will come before "Jan 19," which is probably not what you want.
The raw text solution is simply:
ws.Cells[1, 1].NumberFormat = "#";
ws.Cells[1, 1].Value = "Jan 19";
Presumably, you mean January 2019, in which case any reasonable date format (based on your locale) would result in a date within January, and then a format of mmm yy would render that as "Jan 19:"
ws.Cells[2, 1].Value = "1-Jan-2019";
ws.Cells[2, 1].NumberFormat = "mmm yy";
And just to prove this works, the notion of an Excel date (the number of days after 1/1/1900 or something similar) should even work directly:
ws.Cells[3, 1].Value = "43466";
ws.Cells[3, 1].NumberFormat = "mmm yy";
These last two methods will retain the format you desire and still treat the cells as values that enable sorting and math.
Here are the results of the above three statements:
Interestingly I am guessing the "Jan-19" was probably translated to 1/19/2018, which I am guessing is not what you intended.

Related

Local Time Format in Excel

I'm using c# to import same data in Excel and on of the cell in each row has date time
var dataToImportToExcel= new object[1048576, 10] //Array of data
foreach(...)
{
...
dataToImportToExcel[row, columnIndex++] = UnixTime.LocalTimeToDateTime(time)
...
}
Here UnixTime is defined as Epoch.AddMilliseconds(unixTimeStamp)
After creating the above variable it's passed to current worksheet
var writeRange = currentWorkSheet.Range[i, j];
writeRange.Value2 = dataToImportToExcel;
Excel is showing date time format as 02/05/2021 06:04:37.000 pm instead of 5/2/2021 6:04:35 pm, here later on is the local date time format. Even if I change local date time format in machine it always uses first format only.
While debugging I can see in the IDE that date format is correctly showing in variable dataToImportToExcel
It looks your Excel understood that you wrote a DateTime value into the cell.
It's format is not defined by the value but by the formatting information set on Cell or Range. Looking into How to make correct date format when writing data to Excel topic you should set it like this:
Range rg = (Excel.Range)worksheetobject.Cells[1,1];
// Instead of "MM/DD/YYYY" you may use a format specifier appropriate for your needs.
rg.EntireColumn.NumberFormat = "MM/DD/YYYY";
This will format the entire column in the same way. Following the topic above you will find other examples like setting only one cell's format.

Print a DateTime with the same culture format as it was parsed from but with a shorter year component

There are many different ways of representing dates, based on the culture you're using.
Let's say I take the US date for January 2nd, 2018: "1/2/2018".
I want to make a method that returns the same value in the same culture format but with only two digits for the year component.
For example:
dd/mm/yyyy -> dd/mm/yy
mm/dd/yyyy -> mm/dd/yy
yyyy-mm-dd -> yy-mm-dd
I want to take a DateTime variable and return the same date variable in the same culture but with the year in the format yy.
Is it ok for every culture if i do something like this?
var year = mydate.ToShortDate.ToString("yy");
var date = mydate.ToShortDate.Substring(0, mydate.Count() - 4) + year;
My input will be .ToShortDate() in many cultures
There is no proper way to do this as far as I know, so the following should be considered a hack.
Let's assume that the date is held in a DateTime. How it got there is not important.
Now the task is to convert it to a string representation according to the short date format, whatever that might be, but with yyyy instead of yy.
http://www.basicdatepicker.com/samples/cultureinfo.aspx
It looks like short date formats contain either yyyy or yy in pretty much all cultures, so let's make that assumption.
The conversion can now be done in this way.
var sampleDate = new DateTime(1992, 12, 31);
var formatString = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
var newFormatString = formatString.Replace("yyyy", "yy");
var sampleDateAsString = sampleDate.ToString(newFormatString);
If the original format string does not contain "yyyy", then the new format string will be the same as the original.
Of course you can get the ShortDatePattern for any culture, not only the current culture as shown here.

How to correctly render a ar-SA date and time string

So, I've got a DateTime value, and I need to render it out using the ar-SA culture (using the Gregorian Calendar).
The format I'd like to use is dd-MMM-yyyy HH:mm.
I'm using this currently to format it -
dateTimeValue.ToString("dd-MMM-yyyy HH:mm", culture)
In en-GB, I'd see -
06-Jun-2017 16:49
In ar-SA, when I use the same method, I see -
06-يونيو-2017 16:49
Now, from what I can work out, I think it's the RTL string that's causing the problem, since it's always on the right-hand side.
How do I render out this date correctly in RTL?
Right, after a bit of digging, I've managed to get a solution that works.
Even though my question was originally about ar-SA, it does apply to any right-to-left culture.
I ended up using unicode characters to explicitly state what parts of the string were left-to-right and right-to-left.
So, using the constants -
private const char LeftToRightCharacter = (char)0x200E;
private const char RightToLeftCharacter = (char)0x200F;
I can then build up a string of the date as follows -
if (culture.TextInfo.IsRightToLeft)
{
return
LeftToRightCharacter +
date.ToString("yyyy-", culture) +
RightToLeftCharacter +
date.ToString("MMM", culture) +
LeftToRightCharacter +
date.ToString("-dd", culture);
}
return date.ToString("dd-MMM-yyyy", culture);
...where culture is a CultureInfo (with the DateTimeFormat.Calendar set to new GregorianCalendar()) and date is a DateTime.
So, for the date 06-Jun-2017, in en-GB I get -
06-Jun-2017
and in ar-SA I get -
2017-‏يونيو‎-06
Now that I've got that as a string, I can add the time on either side (to the left, if the culture is RTL and on the right if the culture is LTR).
It was useful seeing how Unicode deals with these characters, along with the other characters I could have used instead - http://www.unicode.org/reports/tr9/
CultureInfo CurrentCulture = CultureInfo.GetCultureInfo("ar-AE");
string text = DateTime.Now.ToString("yyyy MMMM dd", CurrentCulture);
var dt = DateTime.Parse("31/1/2016 12:00 AM", CultureInfo.GetCultureInfo("ar-SA"));
// Throws FormatException
And you can't parse this string with ar-SA culture because this culture uses ص as a AMDesignator since it uses UmAlQuraCalendar rather than a GregorianCalendar.
You can use InvariantCulture (which uses AM as a AMDesignator and uses GregorianCalendar) instead with DateTime.ParseExact method with specify it's format exactly.
string s = "31/1/2016 12:00 AM";
DateTime dt = DateTime.ParseExact(s, "dd/M/yyyy hh:mm tt",CultureInfo.InvariantCulture);
Reference here. Someone had the same problem as you more or less and this seemed to have solved the error. Hope this helps.
To render it go have a look here and here. They seemed to have a similar issue with the rendering that may be able to resolve your issue.
The ar-SA short date pattern is:
d[U+200F]‏/M‏[U+200F]/yyyy g for dotnet v6.0.1
MM/dd/yyyy for date-fns/locale/ar-SA v4.26
U+200F is the Right-To-Left mark character.
It shows up as "d‏/M‏/yyyy g" if you print it out.
Not sure what is the final "g", maybe the era (in case why it is not "G"?)
Also the "g" is not accepted by the date-fns.format() function and raises an error.
open System
open System.Globalization
open System.IO
let culture = CultureInfo.GetCultureInfo("ar-SA")
let pattern = culture.DateTimeFormat.ShortDatePattern
let date1 = DateTime(2017, 6, 6).ToString(pattern)
let date2 = DateTime(2017, 6, 6).ToString(pattern, culture)
use writer = File.CreateText("C://temp//ar-SA date.txt")
writer.WriteLine $"Short date1: {date1}"
writer.WriteLine $"Short date2: {date2}"
Result, copy paste from notepad++:
Short date1: 6‏/6‏/2017 AD <- bad rendering here in the post
Short date2: 11‏‏/9‏‏/1438 بعد الهجرة <- bad rendering here in the post
In notepad++ the "6" and "11" appears in the right place:
So, the "wrong" position seems to really be a matter of where the date is printed (HTML, text file ...).
When you change the culture of the current thread it correctly uses the Hijri calendar so the year is 1438.
I added an extra RLM marker to the pattern (before the day):
"‏[U+200F]d[U+200F]‏/M[U+200F]‏/yyyy g"
and it came out correct both in notepad++ and copy-pasted here:
Short date3: ‏11‏‏/9‏‏/1438 بعد الهجرة

Strange behavior when converting String to DateTime

Im experiencing strange behavior when converting String to DateTime and then again ToString().
Convert.ToDateTime("16-02-2012").ToString("MM/dd/yyyy") results in 02-16-2012
Convert.ToDateTime("16-02-2012").ToLongDateString() results in 16. februar 2012
As you can see the conversion is correct when using ToLongDateString() but somehow the / is converted to - when using ToString().
When I insert the first result into a Excel sheet the value is actually '02-16-2012 (notice the ' in the beginning)
When I use a date where the first segment is lower than 12 the result contains / as expected but is reverted to dd/MM/yyyy.
I've tried using new System.Globalization.CultureInfo("da-DK", false) when converting ToDateTime() but with no effect (Our system is already set to da-DK - but I got desperate).
Anyone seen this behavior before?
EDIT
To clarify my post a little, the date format in danish is dd-mm-yyyy (which I want to format to mm/dd/yyyy) - I know that the first segment is month in a english date.
Change
Convert.ToDateTime("16-02-2012").ToString("MM/dd/yyyy")
to
Convert.ToDateTime("16-02-2012").ToString("dd/MM/yyyy")
It's just a typo.
If that's not what you want, try this:
DateTime.Parse("16-02-2012", CultureInfo.CreateSpecificCulture("da-DK"));
Then you can add whatever .ToString(...) you want on the end.
Edit 2: Your computer is outputting the date in your own culture. If you want it parsed and displayed correctly, you need to provide culture info for each operation.
Console.WriteLine(DateTime.Parse("16-02-2012", CultureInfo.CreateSpecificCulture("da-DK")).ToString(CultureInfo.CreateSpecificCulture("da-DK")));
// 16-02-2012 00:00:00
To export the data in the format you want, you can insert the data as DateTime and use a cell format like in the following example (assuming your dates are in column A):
Application Excel = new Application();
Workbook workbook = Excel.Workbooks.Add(1);
Worksheet sheet = workbook.Sheets[1];
sheet.Cells[1, 1] = DateTime.Now;
sheet.Cells[2, 1] = DateTime.Now.AddDays(1);
sheet.Cells[3, 1] = DateTime.Now.AddDays(2);
sheet.UsedRange.Columns["A:A", Type.Missing].NumberFormat = "MM/dd/yyyy";
workbook.Sheets.Add(sheet);
// Save the workbook or make it visible

DateTime.ToString formatting

I'm displaying localized short dates by providing culture info to DateTime.ToString method. By now I was using
x.ToString("d", ci); // 23.12.2000
that displays short date. But now I would like to also include abbreviated day name. I tried
x.ToString("ddd d", ci); // pon 23
but now d becomes day specifier instead of short date format so instead of day name and short date I only get day name and day number.
How do I convince formatter to display day along with predefined culture short date format?
How about:
string.Format(ci, "{0:ddd} {0:d}", x)
The "standard" formatting strings work by obtaining the equivalent property of the CultureInfo's DateTimeFormat. In this case "d" finds the ShortDatePattern property, which will be something like "dd.MM.yyyy", "dd/MM/yyyy", "MM/dd/yyyy", "yyyy-MM-dd" and so on, depending on that locale in question.
Hence you can make use of it in a custom pattern like so:
x.ToString("ddd " + ci.DateTimeFormat.ShortDatePattern, ci) // Sat 2000-12-23 on my set up, should presumably be pon 23.12.2000 on yours
x.ToString("ddd ", ci) + x.ToString("d", ci);
If nothing else, you could: x.ToString("ddd", ci) + " " + x.ToString("d", ci);
Take a look at this explanation:
http://www.csharp-examples.net/string-format-datetime/
Maybe you can find some examples there.
Update
As response to the comment, Example 3 in the first codeblock clearly states how to do this:
String.Format("{0:d dd ddd dddd}", dt); // "9 09 Sun Sunday" day
Googling a question about date to string formatting, and hitting this question will be much more valuable if there is a reference to good examples. Hence the reference to the csharp-examples site.

Categories