Recently (nobody noticed it happening before, if it did) some "ID"-type values are being converted by Excel to dates. There is some logic to which values are being converted, as you can see here, where the user added a column to show what the underlying values really are, and how they should be represented (raw, no conversion):
So because there's a "-" after "01" Excel is thinking that "01-" should be January, an assuming the final two characters represent the year.
In Item codes that contain no dash, they are left alone. How can I prevent Excel from being "helpful" in this way and converting these values to dates?
UPDATE
In response to Scott Craner's comment, this is the code I have to write out that value:
using (var memberItemCodeCell = priceComplianceWorksheet.Cells[rowToPopulate, DETAIL_MEMBERITEMCODE_COL])
{
memberItemCodeCell.Style.Font.Size = DATA_FONT_SIZE;
memberItemCodeCell.Value = _memberItemCode;
memberItemCodeCell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
}
...and when I try to figure out how to format the value as Text or General by typing "for" after the cells name, I see these options:
So what do I need to use - FormatedText (sic) or ConditionalFormatting, and how specifically do I set those up to format the column as Text or General, and which if any of these two are preferred?
I generally when preparing the table to put data, I define data type so Excel don't try to find the kind of data.
In this case I would use Text data type. Example:
I think you want to change the number format to text.
The text format is specified with the NumberFormat property using the "at" character.
memberItemCodeCell.Style.Font.Size = DATA_FONT_SIZE;
memberItemCodeCell.NumberFormat = "#";
memberItemCodeCell.Value = _memberItemCode;
memberItemCodeCell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
Also, for what it's worth, take a look at articles / questions regarding the difference between Value and Value2. It's good to understand the difference and use the proper one. In your case, I doubt it matters.
What ended up working for me was using this technique to assign the proper data type to the value in the cell (with the call to ConvertValueToAppropriateTypeAndAssign()) and then formatting as necessary after the fact:
public static readonly string NUMBER_FORMAT_CURRENCY = "$#,##0.00;($#,##0.00)";
public static readonly string NUMBER_FORMAT_THOUSANDS = "#,##0";
public static readonly string PERCENTAGE_FORMAT = "0.00%;[Red]-0.00%";
public static readonly string NUMBER_FORMAT_TEXT = "#";
public static readonly string NUMBER_FORMAT_DOUBLE = "0.00";
. . .
using (var percentageCell = priceComplianceWorksheet.Cells[rowToPopulate, SUMMARY_PERCENTAGE_COL])
{
ConvertValueToAppropriateTypeAndAssign(percentageCell, totalPercentage);
percentageCell.Style.Numberformat.Format = PERCENTAGE_FORMAT;
}
. . .
// Adapted from https://stackoverflow.com/questions/26483496/is-it-possible-to-ignore-excel-warnings-when-generating-spreadsheets-using-epplu
public static void ConvertValueToAppropriateTypeAndAssign(this ExcelRangeBase range, object value)
{
string strVal = value.ToString();
if (!String.IsNullOrEmpty(strVal))
{
decimal decVal;
double dVal;
int iVal;
if (decimal.TryParse(strVal, out decVal))
range.Value = decVal;
if (double.TryParse(strVal, out dVal))
range.Value = dVal;
else if (Int32.TryParse(strVal, out iVal))
range.Value = iVal;
else
range.Value = strVal;
}
else
range.Value = null;
}
Related
EDIT: i have problem which i cant solve. I have large text file. I want select from this file only special data for me.
My code:
class Program
{
static string ticket = "";
static string openTime = "";
static string type = "";
static float size;
static string item = "";
static float price;
static string closeTime = "";
static float priceC;
static float commission;
static float swap;
static float trade;
static void Main(string[] args)
{
ReadFile.ReadAllFile("..\\..\\..\\File.txt");
}
}
public static class ReadFile
{
public static string ReadAllFile(string file)
{
string content = "";
using (StreamReader sr = new StreamReader(file))
{
content = sr.ReadToEnd();
}
Console.WriteLine(content);
return content;
}
}
One line from text file:
18388699 2021.09.03 14:40:14 buy 0.01 eurusd 1.18720 1.16211 1.17961 1.17201 0.00 -0.69 -12.96
In this text there are spaces. I want split this values to my strings.
This code reads the whole text from this text file. But i need select only data to my string from this file. Is there some method or funkcion which can select only important text passages?
Sorry for previous post, i dont want whole script. I am sreaching for some tips and tricks how to do that :D English is not my native language, then i cant describe my problem perfectly, but i tried my best :D
I would probably do something like this:
static void Main()
{
foreach (var line in File.ReadLines(#"..\..\..\File.txt"))
{
var fields = line.Split();
var ticket = fields[0];
var openTime = DateTime.Parse(fields[1] + " " + fields[2], CultureInfo.InvariantCulture);
var price = decimal.Parse(fields[6], CultureInfo.InvariantCulture);
Console.WriteLine($"{ticket}, {openTime}, {price}");
}
}
Read each line of the file using File.ReadLines().
Split on spaces using String.Split().
Index into the fields to get at the data you want.
ticket is just the first field.
For openTime you need to join the second and third field. I also chose to parse to a DateTime.
For things like prices and quantities I would use a decimal data type. In your code you have a float, I would not use that. float's have very low precision, you might get round off error with those. double's are better, but might still have the same problem. The recommended data type for calculations like these is decimal.
I'm reading rows from excel into a model , and excel returns the input such as "10%" or "20%" as "0.1" ,"0.2" string . What is the best way to convert that string into a string such as "20%" , "10%" and to avoid unnecessary conversions, in order not to lose on the performance ? So just to clarify i need to convert string to a string but the program is not letting me obviously . I could convert that string to double then convert that double to string with ToString("#0.##%"), but I would like to know if there is a faster way .
This is the code that reads row and formats excel columns into model props types
static T ReadRow<T>(ExcelWorksheet worksheet, int rowNum)
{
var o = (T)Activator.CreateInstance(typeof(T));
int colNum = 1;
foreach (var p in typeof(T).GetProperties())
{
if (worksheet.Cells[rowNum, colNum].Value != null)
{
p.SetValue(o, Convert.ChangeType(worksheet.Cells[rowNum, colNum].Value, p.PropertyType));
}
colNum++;
}
return o;
To expand on what prachi has put with a solution to converting the string to your desired result.
string val = "0.2"; // for reference
string.Format("{0}%", Convert.ToDouble(val) * 100);
The reason you are getting 10% as .01 is that the number is stored as .01 only and when reading excel you will get its actual stored value. You see it as 10% because its formatted as % in excel.
To read the percent: 10% as string '10%' you will have to format the string when reading.
I am trying to convert an object (coming from a SQL server), into a integer so I can format the number to have the correct amount of zero's in front of it.
For example:
If I were to have 25.6, I would need it to be 0025.6.
Now I have looked online on how to do this, but the methods that I have seen people post are not working for me. I am not entirely sure why. I am trying to format GlobalVariables.grossweightafter. I read the value GlobalVariables.grossweight from the SQL server, but then when I TryParse it, it loses its value. The code I have is below:
while (TransferRecord.Read())
{
//Pulling data from the SQL server. getting data for every line of code as specified.
GlobalVariables.baledate = TransferRecord["keyprinter_datetime"];
GlobalVariables.baleline = TransferRecord["pulp_line_id"];
GlobalVariables.baleid = TransferRecord["bale_id"];
GlobalVariables.grossweight = TransferRecord["bale_gross_weight"];
GlobalVariables.grossweightflag = TransferRecord["gross_value_flag"];
GlobalVariables.baleairdrypercent = TransferRecord["bale_airdry_pct"];
GlobalVariables.airdryflag = TransferRecord["airdry_value_flag"];
//Converting the date, and the baleid to fit in the string.
DateTime.TryParse(GlobalVariables.baledate.ToString(), out GlobalVariables.baledateafter);
int.TryParse(GlobalVariables.baleid.ToString(), out GlobalVariables.baleidafter);
int.TryParse(GlobalVariables.grossweight.ToString(), out GlobalVariables.grossweightafter);
GlobalVariables.grossweightafter.ToString("0000.0");
//Calling the WriteData method.
WriteData();
}
So I was wondering if anyone can catch what I am doing wrong, or they can help me out on the correct way to go about this.
What #Hans Passant was saying is that you need to assign the value returned from .ToString. That line should be:
GlobalVariables.grossweightafter = GlobalVariables.grossweightafter.ToString("0000.0");
The last lines should be
if(int.TryParse(GlobalVariables.grossweight.ToString(), out GlobalVariables.grossweightafter))
{
string grossWeightAfter = GlobalVariables.grossweightafter.ToString("0000.0");
//you need to save the string returned from the ToString-method somewhere or it will be lost.
///Alternatively, if GlobalVariables can contain strings aswell:
GlobalVariables.grossweightafter = GlobalVariables.grossweightafter.ToString("0000.0");
}
else
{
//React on value not being an int
}
Maybe you should try to use double.TryParse() method instead of int.TryParse(), because int does not have fractional part?
Also, you need to store ToString() result to a string variable. Your code should be like this:
GlobalVariables.grossweightafterstring = GlobalVariables.grossweightafter.ToString("0000.0");
Is there any way to make
TypeDescriptor.GetConverter.ConvertFromString convert to DateTime using a custom format e.g. "2011-04-21 13-03-56"?
If not, is there any DateTime-format out there that can be applied to a folder name (/,\,:,etc. are not allowed as you know)?
Help is very much appreciated. Thanks in advance
Random-I-Am
Edit:
Since my request still seems to not be understood correctly I am again trying to elaborate on my question. My users are creating folders with specific names. For example "1000_Link_Topic1_2011-01-25 14-12-10". They are free to combine their information as they like and omit information where needed. They don't even have to care about case sensitivity. So I could face another folder named "1000_link_Topic2".
What I have is a single class with a single property for each possible fragment of information. In this case I would have (Since I had to find a way of checking each properties default value regardless of the property type I am using nullable types):
Short? short_val;
EContentType? enum_val;
String string_val;
DateTime? datetime_val;
My code obviously splits the folder name at "_" and then tells for each fragment to which of the above property types it belongs. As soon as I know the corresponding type I am trying to convert to the Type, lets say t, using TypeDescriptor.GetConverter(t).ConvertFromString(info_frag[i]). I hope you now understand why I cannot use another conversion Method.
The code works for all the types mentioned above. My problem is to find a custom DateTime format that can be used on a folder name. All of the formats I know are using colons to separate hours from minutes and seconds.
What I want is a way to convert from a custom DateTime-format to a DateTime-object using TypeDescriptor.GetConverter.ConvertFromString. If that is not possible I either need to find a standard DateTime-format which can be assigned as a folder name without any further conversion or somehow extend the built-in DateTime-formats by my custom format. If it is going to be the latter I do not care about being able to use seconds or minutes. Hours will do the job.
Thanks again for being as patient as you are and helping me out with this one. Feel free to ask as many further questions as you like. I hope you can help me getting this one to work.
Random-I-Am
I have looked into your problem a little and found that the standard DateTimeTypeConverter uses DateTime.Parse internally which doesn't listen to CurrentCulture info at all. Instead you can trick the conversion process with your own TypeConverter!
I do not know how to attach the new typeconverter to the existing DateTime structure, if you even can, so I made a miniture AdvancedDateTime structure .. which is empty. Noone said your custom TypeConvert should even return such a thing! This one returns a regular DateTime. I provided the code below:
public class CustomDateTimeTypeConverter : TypeConverter
{
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
return DateTime.ParseExact(value.ToString(), "yyyy-MM-dd HH-mm-ss", culture);
}
}
[TypeConverter(typeof(CustomDateTimeTypeConverter))]
struct AdvancedDateTime
{
}
[TestFixture]
public class DateTime
{
[Test]
public void TypeConvert_StrangeFormat_ConvertsWithoutProblem()
{
string datetime = "2011-04-21 23-12-13";
TypeConverter converter = TypeDescriptor.GetConverter( typeof (AdvancedDateTime) );
var convertedFromString = converter.ConvertFromString(datetime);
Assert.AreEqual(new DateTime(2011,4,21, 23,12,13), convertedFromString);
}
}
Try this
string m_strDate = DateTime.Now.ToString("MM/dd/yyyy");
m_strDate = m_strDate.Replace("/", "");
Append this m_strDate to your folder
A sample i used for text file is as follows
strPath += "/FileHeader_" + m_strDate + ".txt";
Check this sample
DateTime dt=new DateTime(1990,5,6);
Console.WriteLine(TypeDescriptor.GetConverter(dt).ConvertTo(dt, typeof(string)));
string myStr="1991-10-10";
Console.WriteLine(TypeDescriptor.GetConverter(dt).ConvertFrom(myStr));
The sample code i written just to display as per you need try as per your requirement
string s = "Folder";
DateTime dt = new DateTime(1990, 5, 6);
string str = TypeDescriptor.GetConverter(dt).ConvertTo(dt, typeof(string)).ToString();
string myStr = "1991-10-10";
string str1 = TypeDescriptor.GetConverter(dt).ConvertFrom(myStr).ToString();
s = s + str1.Replace("/", "").Replace(":", "");
textBox1.Text = s;
I'm writing a small app to do a little processing on some cells in a CSV file I have. I've figured out how to read and write CSV files with a library I found online, but I'm having trouble: the library parses CSV files into a DataTable, but, when I try to change a cell of the table, it isn't saving the change in the table!
Below is the code in question. I've separated the process into multiple variables and renamed some of the things to make it easier to debug for this question.
Code
Inside the loop:
string debug1 = readIn.Rows[i].ItemArray[numColumnToCopyTo].ToString();
string debug2 = readIn.Rows[i].ItemArray[numColumnToCopyTo].ToString().Trim();
string debug3 = readIn.Rows[i].ItemArray[numColumnToCopyFrom].ToString().Trim();
string towrite = debug2 + ", " + debug3;
readIn.Rows[i].ItemArray[numColumnToCopyTo] = (object)towrite;
After the loop:
readIn.AcceptChanges();
When I debug my code, I see that towrite is being formed correctly and everything's OK, except that the row isn't updated: why isn't it working? I have a feeling that I'm making a simple mistake here: the last time I worked with DataTables (quite a long time ago), I had similar problems.
If you're wondering why I'm adding another comma in towrite, it's because I'm combining a street address field with a zip code field - I hope that's not messing anything up.
My code is kind of messy, as I'm only trying to edit one file to make a small fix, so sorry.
The easiest way to edit individual column values is to use the DataRow.Item indexer property:
readIn.Rows[i][numColumnToCopyTo] = (object)towrite;
This isn't well-documented, but DataRow.ItemArray's get accessor returns a copy of the underlying data. Here's the implementation, courtesy of Reflector:
public object[] get_ItemArray() {
int defaultRecord = this.GetDefaultRecord();
object[] objArray = new object[this._columns.Count];
for (int i = 0; i < objArray.Length; i++) {
DataColumn column = this._columns[i];
objArray[i] = column[defaultRecord];
}
return objArray;
}
There's an awkward alternative method for editing column values: get a row's ItemArray, modify those values, then modify the row to use the updated array:
object[] values = readIn.Rows[i].ItemArray;
values[numColumnToCopyTo] = (object)towrite;
readIn.Rows.ItemArray = values;
use SetField<> method :
string debug1 = readIn.Rows[i].ItemArray[numColumnToCopyTo].ToString();
string debug2 = readIn.Rows[i].ItemArray[numColumnToCopyTo].ToString().Trim();
string debug3 = readIn.Rows[i].ItemArray[numColumnToCopyFrom].ToString().Trim();
string towrite = debug2 + ", " + debug3;
readIn.Rows[i].SetField<string>(numColumnToCopyTo,towrite);
readIn.AcceptChanges();