I'm reading an Excel spreadsheet using JXL and Groovy like this:
WorkbookSettings settings = new WorkbookSettings();
settings.encoding = "Cp1252"
settings.locale = new Locale("pt", "BR")
Workbook workbook = Workbook.getWorkbook(is, settings)
Sheet sheet = workbook.getSheet(0)
And then I have a cell in Excel which value is 09/01/2013 (dd/mm/yyyy). But then, when I retrieve cell contents, JXL automatically does some conversion and gives this back at me:
"09/01/13" == sheet.getCell(col, line).contents?.trim()
But then, when I cast the Cell to a DateCell, the Date representation of "09/01/13" becomes Jan 8, 2013 (!):
DateCell dc = ((DateCell) sheet.getCell(col, line))
println "date from JXL: ${dc.date}" // prints Tue Jan 08 22:00:00 BRST 2013
Would anyone have any ideas about how to fix this? If I could just retrieve the actual cell contents directly (09/01/2013), then I could do all the conversion stuff by myself.
Thanks!
From: http://www.andykhan.com/jexcelapi/tutorial.html#dates
When displaying dates, the java.util package automatically adjusts for the local timezone. This can cause problems when displaying dates within an application, as the dates look as if they are exactly one day previous to that which is stored in the Excel spreadsheet, although this is not in fact the case.
...
The easiest way to work around this (and the method used internally by the getContents() method of a jxl.DateCell) is to force the timezone of the date format as follows:
TimeZone gmtZone = TimeZone.getTimeZone("GMT");
SimpleDateFormat format = new SimpleDateFormat("dd MMM yyyy");
format.setTimeZone(gmtZone);
DateCell dateCell = ....
String dateString = format.format(dateCell.getDate());
Related
I made a few functions with GoogleSheets using AppsScripts for simple task a few times in previous years. I always had problems when taking dates from cells/ranges and processing them, but somehow alwaays found a workaround, so that I did not have to deal with it. Well, this time I can not find a workaround, so I will try to explain my problems with the following code:
function getDates(){
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('Dates');
var date = sht.getRange(2,1).getValues();
Logger.log(date[0][0]); //output is Tue Jun 08 18:00:00 GMT-04:00 2021
var datumFilter= Utilities.formatDate(date[0][0], "GMT+1", "dd/mm/yy");
Logger.log(datumFilter); //output is 08/00/21
var outrng = sht.getRange(25,1);
outrng.setValue(date);
}
The first targeted cell ('var date') has a value of "9.6.21" in the spreadsheet. The cell is formatted as a date and it opens a calendar when double-clicked. When I set the new cells values (with 'outrng.setValue(date);'), the result is OK, with the same date as in the original cell.
But I do not need to simply transfer the values, I want to implement them in some loops and I have no idea how to simply get the date in the same format or at least the same date in the script as it is in the cell. As you can see from the logger, the values there are different. A simple d/m/yy format would be sufficient.
My spreadsheet settings are set to my local time (Slovenia, GMT+1).
I am guessing that I am missing some basics here. I have spent many hours trying to understand it, so any help is highly appreciated!
Cooper already answered all your questions in the comment. I'd like to add on and show you an example on what it would like and add some modifications.
Code:
function getDates() {
var s = SpreadsheetApp.getActiveSpreadsheet();
var sht = s.getSheetByName('Dates');
// get last row of the sheet
var lastRow = sht.getLastRow();
// get your sheet's timezone
var timezone = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var output = [];
// getValues is mostly used for multiple cells returning a 2D array
// use getValue for single cells to return its actual value
// but since function name is getDates, I assume column A is all dates
// so we fetch the whole column (A2:A[lastRow]) except the header
var dates = sht.getRange("A2:A" + lastRow).getValues();
// for each date on that column, we format the date to d/M/yy
// m/mm = minute
// M/MM = month
dates.forEach(function ([date]){
Logger.log(date);
var datumFilter= Utilities.formatDate(new Date(date), timezone, "d/M/yy");
Logger.log(datumFilter);
// collect all dates in an array
output.push([datumFilter]);
});
// assign all the dates in the array onto range B2:B
sht.getRange(2, 2, output.length, 1).setValues(output);
}
Sample data:
Logs:
Output:
Note:
The output on sheets is not equal to logs due to the formatting of my sheet.
I need to add Excel style automatic date creation, based on a user input in Word. After accessing development menu I can insert a date picker menu control from the dev menu. This provides a simple and easy to enter date format. I then wish to take the user selected value and add additional dates based on that date selection, increased by a number of days, and have these dates automatically appear into another area of the document. I have not been successful in searching online. Does anyone know of a solution to this?
For that, you'll need a ContentControlOnExit macro coded along the lines of:
Private Sub Document_ContentControlOnExit(ByVal CCtrl As ContentControl, Cancel As Boolean)
Dim DtVal As Date, Fmt As String
With CCtrl
If .Type = wdContentControlDate Then
Fmt = .DateDisplayFormat
.DateDisplayFormat = "MMM-DD-YYYY"
DtVal = CDate(.Range.Text)
.DateDisplayFormat = Fmt
With ActiveDocument
.SelectContentControlsByTitle("Date1")(1).Range.Text = Format(DtVal + 5, "MMM D, YYYY")
.SelectContentControlsByTitle("Date2")(1).Range.Text = Format(DtVal + 21, "MMM D, YYYY")
.SelectContentControlsByTitle("Date3")(1).Range.Text = Format(DtVal + 90, "MMM D, YYYY")
End With
End If
End With
End Sub
and inserted into the 'ThisDocument' code module of the document or its template, where the output text content controls are titled Date1, Date2, Date3, etc.
I am using google apps script for a google sheet that is meant to sort ranges of cells into different sheets by date. I've entered a date in the cell A2, and then when I use my function, it sorts the sheet with the same date as what is in A2, and if there isn't one, then it will create a new sheet with that date. The problem that I am coming across is not with the cells getting to the right place, but for some reason the date changes to what seems to be an id of sorts. For example, for the date 01/01/2001, the first couple worked fine, and then for the next couple attempts it switched to have "36892" where the date should be.
I have not tried anything, as I am unsure of what to try. If I knew the command, I would just switch the format back after moving the cells to the right place.
function findDate() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
ss.setActiveSheet(ss.getSheets()[0])
var range = sheet.getRange("A2");
var A2 = SpreadsheetApp.getActiveSheet().getRange('A2').getValue();
var templateSheet = ss.getActiveSheet();
var val = Utilities.formatDate(new Date(A2), "GMT+1", "MM/dd/yyyy");
range.setValue(new Date(A2)).setNumberFormat("MM/dd/yyyy");
A2 = SpreadsheetApp.getActiveSheet().getRange('A2').getValue();
if( ss.getSheetByName(val) == null)
{
//if returned null means the sheet doesn't exist, so create it
ss.insertSheet(val, ss.getSheets().length, {template: templateSheet});
}
else
{
var sheet1 = ss.getSheetByName("GUI");
var sheet2 = ss.getSheetByName(val);
sheet1.getRange("A2:D2").copyTo(sheet2.getRange(sheet2.getLastRow()+1,1,1,4), {contentsOnly:true});
}
ss.setActiveSheet(ss.getSheets()[0]);
sheet.getRange("A2:D2").clearContent();
}
This is my function. Since I don't know where the problem lies, I copied the whole thing, sorry about the bulk.
Date Event Time Comments
01/01/2001 Movie 22:00 a
01/01/2001 Movie 11:00 PM a
36892 Movie 0.7083333333 a
36892 Movie 12:00 PM a
This was the result from adding the same date each time, and sorting them to the correct sheet using the function. The time is being odd, I really have no clue why, but I don't really care at this point, that's a future problem (unless anyone has any clue why it changes format too). The date, however, doesn't seem to be some random number as the same date gave the output of the same number. I would have expected it to look like:
Date Event Time Comments
01/01/2001 Movie 10:00 PM a
01/01/2001 Movie 11:00 PM a
01/01/2001 Movie (I forget) a
01/01/2001 Movie 12:00 PM a
Answer:
You need to remove {contentsOnly:true} from your copyTo() method.
Reasoning:
By setting the contentsOnly boolean to true you're telling sheets to copy what it sees in the cell, not what you see.
In Sheets, all days are serialized starting from the 1st January 1900 with a day of 1, so copying 01/01/2001 is day with serial number 36892.
As for the date - it's being read as a fraction of how far through the day it is - at 17:00h and with 24 hours in the day the date will be seen as 17/24 or 0.708333333333.
I have the following code
String test = "21/04/2013";
fmt = DateTimeFormat.getFormat("MM/dd/yyyy");
Date dateTest = fmt.parse(test);
Window.alert(fmt.format(dateTest));
And the alert box shows the date
09/04/2014
instead of
21/04/2013
Why?
As others already say, it's because of your pattern. What they don't say is why it behaves that way.
When parsing 21/04/2013 as MM/dd/yyyy, DateTimeFormat will decompose the date as:
Month Day of month Year
21 4 2013
and it'll then adjust things to make a valid date. To do that, the Month part is truncated at 12 (so that temporary date is Dec 4th, 2013) and the remainder (21 - 12 = 9) is then added, leading to Sept. 4th 2014, which according to your format displays as 09/04/2014.
You wanted to show 21/04/2013 but the format was MM/dd/yyyy.
It should be dd/MM/yyyy
So change it like this:
String test = "21/04/2013";
fmt = DateTimeFormat.getFormat("dd/MM/yyyy");
Date dateTest = fmt.parse(test);
Window.alert(fmt.format(dateTest));
You're reversing day and month.
String test = "21/04/2013";
fmt = DateTimeFormat.getFormat("dd/MM/yyyy");
Date dateTest = fmt.parse(test);
Window.alert(fmt.format(dateTest));
I'm trying to enter the Date value by adding a month to the date in Sheets("Sheet1").Cells(17, 3).Value which is 01/10/2011 but format as Oct-11. Then return in Sheets("Sheet1").Cells(17, 4).Value = LDate, to show Nov-11
sDate = Sheets("Sheet1").Cells(17, 3).Value --> this shows 01/10/2011 when I hove over sDate
LDate = DateAdd("m", 1, sDate) --> this shows 01/11/2011 when I hove over LDate
I then want to enter that value 01/11/2011 in to the following cell
Sheets("Sheet1").Cells(17, 4).Value = LDate
Selection.NumberFormat = "mmm-yy"
But in the cell it shows 11/01/2011 (Jan-11), why is it doing this and how can I fix this issue?
Minor issue
Selection.NumberFormat = "mmm-yy"
You have not selected anything so this format is placed wherever you left the cursor.
Major issue
You have hit the Excel bug that it will interpret dates as being in American (middle endian) format if it can when transferring data to a worksheet. "1/11/2011" would be "11 Jan 11" to an American so it is to Excel. "20/11/2011" is not a valid American date so to Excel it is "20 Nov 11".
I can duplicate your problem by declaring sDate and LDate as strings. DateAdd works correctly with strings so LDate is correct but when placed in a cell it is misinterpreted.
I can fix your problem by declaring sDate and LDate as dates:
Dim sdate As Date
Dim Ldate As Date
Selection.NumberFormat = "mmm-yy"
Above line is changing the number format. Actually When am running through your steps, I have come across the same issue.
But Number format is doing all this auto change.
Example:
While am running the macro, assume that selected cell is (17,3).
Before running macro: cell value is 01/11/2012
After running macro: cell value will be changed/formatted as "Jan-12". (Since number format is applied as "mmm-yy", so it consider as 01/11/2012 is consider as Jan-12)
Second time, if you select the cell (17,4)
Before running macro: cell value is 2/11/2012
After running macro: cell value will be changed / formatted as "Feb-12"
Instead of trying
Cells(row2,col2) = Cells(row1,col1)
Try this
Cells(row1,col1).Copy
Cells(row2,col2).PasteSpecial Paste:=xlPasteValuesAndNumberFormats