I need to generate some pretty large excel files, and I was thinking of switching from PHPExcel to spout, since it seems to be much more efficient. I have been able to find every feature I needed, except one: how to format a cell as date. It seems to think that by default everything is a string. For numbers I have found that using intval() or floatval() forces it to consider the value a number, but is there anything similar for dates?
The only workaround I have found so far is to convert the date to a number using (strtotime($datestr)/86400)+25569.4167 , but then you have to manually format the column as a date after exporting the file, but the users will not accept that.
There is no way to format a cell as a date for now. You can always pass a date string (like "03/03/2017"); Excel is usually pretty good at recognizing that this is a date.
Your workaround indeed requires a manual step to configure the column as a date, so I would not recommend doing this.
In the end, I have found this commit on github https://github.com/box/spout/pull/209 where they add the option to format dates and, amongst other things, to format cells individually. I know this is not an official release, and so it is "use at your own risk", but for me it was just what I needed, so I thought to add the link just in case someone else is in the same situation. Warning, though, it does break setting the background color for both a cell and a row, but in my case that wasn't a problem.
Related
I am working with a fairly large, complex spreadsheet (there are 6 sheets, each with 200-400 rows) and am having trouble getting the correct values out of some cells.
My workflow is roughly:
User data is inputted on front-end
Data is validated and then placed into certain cells on the spreadsheet
Calculations in other cells reference the user-input cells
I use getCalculatedValue on particular cells to retrieve the necessary values
For debug purposes I then save out the modified spreadsheet so that I can easily see that the data has been inputted and generated correctly.
PHPExcel has been working great, but I have ran into an issue where the getCalculatedValue method (step 4) is returning an incorrect value, but when I inspect the spreadsheet that has been saved out (step 5) the values are correct.
The calculations consist of general mathematical equations, IF conditions, some date manipulation and multiple VLOOKUPs.
I am currently picking my way through the calculations in order to trace the issue, but was wondering if there may be a simpler solution to this that I am not aware of. Perhaps some setting that affects the outcome of various different calculations? This may even be a subtle change in calculations that is subsequently snow-balling into a bigger change further down the line.
Thanks in advance.
Turned out to be a syntax error in the spreadsheet that I was provided.
A round function was being used like so:
ROUND(NUMBER,)
Excel compensated for this by using 0 as the second parameter, whereas PHPExcel (quite correctly) didn't.
I'm trying to export a CSV with php/mysql, when an amount is in dollars the amount is taken as text.
Is there a work around to have these amounts taken as numbers without additional excel formatting from my php program?
Edit:
The following code is where the amounts are given their respective amounts.
switch($currency)
{
case 'Eur':
$symbol=iconv("UTF-8", "cp1252", "€");
break;
case 'USD':
//$symbol=chr(36);//"$";
$symbol=iconv("UTF-8", "cp1252", "$");
break;
case 'GBP':
//$symbol="£";//chr(163)//;
$symbol=iconv("UTF-8", "cp1252", "£");
break;
case 'EUR':
$symbol=iconv("UTF-8", "cp1252", "€");
break;
}
return $symbol."".$number;
The return is fed to the csv.
Obviously Euro and Pounds are working correctly but Dollar isn't I suspect becouse of the absolute reference function it has.
It's excel who converts the value to text. This all depends on the regional settings of windows. There's no way around it. (As far as I know)
For Example: When I set Standard and formats to English (United States), the cell is formatted as currency (cell value = 1 with $ as currency) and when set to Dutch (Netherlands), the cell is formatted as general (cell value = $1 as text).
I wouldn't really advise storing formatting in CSV files. Although it can cause more work it also leads to more flexibility if you store your data raw. You can always send raw data and convert afterwards.
Keep in mind that CSV is not an Excel format. By forcing your CSV to be Excel compliant, you could even be causing issues for someone who is, say, trying to import CSV onto the web, or something along those lines. Formatting that works for one project (or country, as dn Fer has shown in his answer) may not work for another in the same way.
I think a more important question than "how can I do this?" is, "why should I do this?" If you are going to provide an "Excel-friendly" pre-formatted program then you should offer it in addition to an un-formatted raw CSV file. If you are only going to choose one, let the end user handle the formatting themselves. The alternative will inevitably cause you more issues than it is worth.
My suggestion is to let the column headers do the explaining for you. Put the name of the currency and even the symbol at the top of each column head if you want, and put the totals underneath in raw number form. Your end user should have no trouble formatting it themselves in whatever program they choose to open it with, and it will have far less chance of not converting correctly.
Conversely, you can consider creating an XML file. While it will be much more high-powered if you want it to work in multiple file formats, it will allow you to format as far as your imagination/documentation/experimentation/testing gets you. If you choose to go this route here are some resources I have found:
xml - Foreign currency to Excel xslt (SO)
Features and limitations of Excel spreadsheet format
In the end, I would strongly recommend going the CSV route first. If you want to make something more robust, you can begin developing something different. XML is probably a better format as modern spreadsheets support some version of XML standard. The trade off is that there is time. But in the end, nothing is impossible - just expensive!
Goal: Convert any local date to the according ISO date
My Approach: http://codepad.viper-7.com/XEmnst
strftime("%Y-%m-%d",strtotime($date))";
Upside: Converts a lot of formats really well
Downside / Problem: Converts strings and numbers that are obviously not a date. E.g.
strftime("%Y-%m-%d",strtotime("A")) => 2012-10-29
strftime("%Y-%m-%d",strtotime("1")) => 1970-01-01
Questions:
Is there a better way to identify and convert dates to ISO dates?
Do you know of any library / regex that is capable of do so in php?
PHP's strtotime() function already does a best-effort attempt at taking an arbitrary string and working out what date format it is.
I dislike this function for a number of reasons, but it does do a reasonable job of working things out, given a string of unknown date format as input.
However, even strtotime()'s best efforts can never be enough, because arbitrary date formats are ambiguous.
There is no way to tell whether 05-06-07 is meant to be the 5th of June 2007 or the 6th of May 2007. Or even the 7th June 2005 (yes, some people do write dates like that).
Simple plain truth: It's impossible.
If you want your dates to be reliable in any meaningfuly way, you must abandon the idea that you'll be able to accept arbitrary input formats.
[EDIT]
You say in the comments that the input is coming from a variety of Excel and CSV files.
The only hope you have is if each of those files is consistent in itself. If you know that a file from a given source will have a given input format, you can write a custom wrapper for each file type that you import, and process it for that format. This is a solution I've used myself in the past, and it does work as long as you can predict the format for the file you're processing.
However, if individual files contain unpredictable or ambiguous dates, then you are out of luck: You have an impossible task. The only way you'll avoid having bad data is to kick back to the suppliers of the files and ask them to fix their data.
I think the problems will really arise when faced with dates such as 5-6-2012 when it is unclear whether you are dealing with 5th June, or 6th May and you could be taking input from European countries where DD MM YYYY is the norm.
If you are analyzing just one input field, then you might have a chance of detecting the delimeters and splitting the string up looking for what might look like a real date.
In this case the PHP function checkdate might come in handy as a last ditch double check.
Be aware also that Mysql (if this is where the data is heading) is also quite lenient about what it will put into a DATE field, the delimeters, the absence of leading zeros etc. But still, you have to get the Y M D order correct for it to have a chance.
I suppose the ultimate answer is to disallow free-text input for dates, but give them pickers - but of course you may not be in a position to influence the incoming date ...
I have a task to read datetime from csv file by PHP and store them in mysql database. There are two format of datetime in csv file, the first is DD/MM/YYYY HH:mm:ss AM/PM, the second is MM-DD-YYYY HH:mm:ss AM/PM. Then later, I need to select some rows for their datetime is in some period.
It seems a little confused. There are some questions in my brain:
It is easy to set varchar type in mysql table to store them. But it
is dificult to select some rows later, since I need to convert
string to datetime first and check if data between in a special
period.
Another solution is to convert these datetime from string to
datetime by PHP before storing in database. Then it is easy to
select data later. But the first step is also a little complex.
I do not know if some one has any good ideas about this question, or some experience in similar problems.
Firstly: never ever EVER store dates or date times in a database as strings.
NEVER.
Got that?
You should always convert them to the database's built-in date or datetime data types.
Failure to do this will bite you very very hard later on. For example, imagine trying to get the database to sort them in date order if they're saved as strings, especially if they're in varying formats. And if there's one thing that you can be sure of, when you've got a date in a database, you're going to need to query it based on entries on, after or before a given date. If you weren't going to need to do that sort of thing with them, there wouldn't be much point storing the date in the first place, so even if you haven't been asked to do it yet, consider it a given that it'll be asked for later. Therefore, always always ALWAYS store them in the correct data type and not as a varchar.
Next, the mixture of formats you've been asked to deal with.
This is insanity.
I loathe and detest PHP's strtotime() function. It is slow, has some unfortunate quirks, and should generally be considered a legacy of the past and not used. However, in this case, it may just come to your rescue.
strtotime() is designed to accept a date string in an unknown format, parse it, and output the correct timestamp. Obviously, it has to deal with the existence of both dd-mm-yyyy and mm-dd-yyyy formats. It does this by guessing which of the two you meant by looking at the separator character.
If the date string uses slashes as the separator, then it assumes the format is mm/dd/yyyy. If it uses dashes, then it assumes dd-mm-yyyy. This is one of those little quirks that makes using strtotime() such a pain in normal usage. But here it is your friend.
The way it works is actually the direct opposite of the formats you've specified in the question. But it should be enough to help you. If you switch the slashes and dashes in your input strings, and pass the result to strtotime() it should produce the correct timestamps in all cases, according to the way you've described it in the question.
It should then be simple enough to save them correctly in the database.
However I would strongly recommend testing this very very thoroughly. And not being surprised if it breaks somewhere along the line. If you're being fed data in inconsistent formats, then there really isn't any way to guarantee that it'll be consistently inconsistent. Your program basically needs to just do the best it can with bad data.
You also need to raise some serious questions about the quality of the input data. No program can be expected to work reliably in this situation. Make it clear to whoever is supplying it that it isn't good enough. If the program breaks because of bad data, it's their fault, not yours.
Is there a way to specify your own date pattern besides the included ones (small, medium, full). The main point here is that it should work with i18n. I've tried a couple of things but I couldn't get it to work...
Yii::app()->dateFormatter->format("l d/m/Y",$slide->date_start);
I know about strftime but the problem here is that different hosting providers use different locale string... and you have to customize it...
I'm looking for an elegant way of doing this.
I'd like to display the date in l d/m/Y form...
Update:
Never mind... I've just found out that dateFormatter doesn't use standard php date format...
I think you should measure time solely in Unix Time because Timezones & date formats are a presentation-layer problem. Unix time is always UTC & It's a single number, so easier to pass around in code.
As far the problem of "hosting providers use different locale string", just ask the user his timezone & display according to that. far less error-prone than trying to guess.
For date formatting, have a look at YII's format()
Hope it answers your question
Here's a related yii forum discussion
The yii forum solution worked for me to avoid raw SQL NOW() statements but still produce database-friendly date strings with PHP date() and time() functions which otherwise return integers.
In protected/config/main.php:
...
'params'=>array(
'mysqlDateTimeFormat' => 'Y-m-d H:i:s', # ':u' adds microsecond precision,
...
Then, wherever you want to put a date-time string into a model field use
$myModel->myDate = date(Yii::app()->params['mysqlDateTimeFormat']);
Obviously you can enter the date/time format into the date (or time) functions directly if you prefer.