Improve compatibility of os.date() function

This commit is contained in:
James Roseborough
2013-07-14 17:28:38 +00:00
parent db1c7a17b2
commit 9179e74e36
4 changed files with 67 additions and 65 deletions

View File

@@ -24,7 +24,6 @@ package org.luaj.vm2.lib;
import java.io.IOException; import java.io.IOException;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.TimeZone;
import org.luaj.vm2.Buffer; import org.luaj.vm2.Buffer;
import org.luaj.vm2.Globals; import org.luaj.vm2.Globals;
@@ -139,8 +138,23 @@ public class OsLib extends TwoArgFunction {
case CLOCK: case CLOCK:
return valueOf(clock()); return valueOf(clock());
case DATE: { case DATE: {
String s = args.optjstring(1, null); String s = args.optjstring(1, "%c");
double t = args.optdouble(2,-1); double t = args.isnumber(2)? args.todouble(2): time(null);
if (s.equals("*t")) {
Calendar d = Calendar.getInstance();
d.setTime(new Date((long)(t*1000)));
LuaTable tbl = LuaValue.tableOf();
tbl.set("year", LuaValue.valueOf(d.get(Calendar.YEAR)));
tbl.set("month", LuaValue.valueOf(d.get(Calendar.MONTH)+1));
tbl.set("day", LuaValue.valueOf(d.get(Calendar.DAY_OF_MONTH)));
tbl.set("hour", LuaValue.valueOf(d.get(Calendar.HOUR)));
tbl.set("min", LuaValue.valueOf(d.get(Calendar.MINUTE)));
tbl.set("sec", LuaValue.valueOf(d.get(Calendar.SECOND)));
tbl.set("wday", LuaValue.valueOf(d.get(Calendar.DAY_OF_WEEK)));
tbl.set("yday", LuaValue.valueOf(d.get(Calendar.DAY_OF_YEAR)));
tbl.set("isdst", LuaValue.valueOf(isDaylightSavingsTime(d)));
return tbl;
}
return valueOf( date(s, t==-1? time(null): t) ); return valueOf( date(s, t==-1? time(null): t) );
} }
case DIFFTIME: case DIFFTIME:
@@ -164,8 +178,9 @@ public class OsLib extends TwoArgFunction {
String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all")); String s = setlocale(args.optjstring(1,null), args.optjstring(2, "all"));
return s!=null? valueOf(s): NIL; return s!=null? valueOf(s): NIL;
} }
case TIME: case TIME: {
return valueOf(time(args.arg1().isnil()? null: args.checktable(1))); return valueOf(time(args.arg1().isnil()? null: args.checktable(1)));
}
case TMPNAME: case TMPNAME:
return valueOf(tmpname()); return valueOf(tmpname());
} }
@@ -215,13 +230,17 @@ public class OsLib extends TwoArgFunction {
* formatted according to the given string format. * formatted according to the given string format.
*/ */
public String date(String format, double time) { public String date(String format, double time) {
Calendar d = Calendar.getInstance();
d.setTime(new Date((long)(time*1000)));
if (format.startsWith("!")) {
time -= timeZoneOffset(d);
d.setTime(new Date((long)(time*1000)));
format = format.substring(1);
}
byte[] fmt = format.getBytes(); byte[] fmt = format.getBytes();
final int n = fmt.length; final int n = fmt.length;
Buffer result = new Buffer(n); Buffer result = new Buffer(n);
byte c; byte c;
Date date = new Date((long)(time*1000));
Calendar d = Calendar.getInstance();
d.setTime(date);
for ( int i = 0; i < n; ) { for ( int i = 0; i < n; ) {
switch ( c = fmt[i++ ] ) { switch ( c = fmt[i++ ] ) {
case '\n': case '\n':
@@ -234,8 +253,7 @@ public class OsLib extends TwoArgFunction {
if (i >= n) break; if (i >= n) break;
switch ( c = fmt[i++ ] ) { switch ( c = fmt[i++ ] ) {
default: default:
result.append( (byte)'%' ); LuaValue.argerror(1, "invalid conversion specifier '%"+c+"'");
result.append( (byte)c );
break; break;
case '%': case '%':
result.append( (byte)'%' ); result.append( (byte)'%' );
@@ -247,7 +265,6 @@ public class OsLib extends TwoArgFunction {
result.append(WeekdayName[d.get(Calendar.DAY_OF_WEEK)-1]); result.append(WeekdayName[d.get(Calendar.DAY_OF_WEEK)-1]);
break; break;
case 'b': case 'b':
case 'h':
result.append(MonthNameAbbrev[d.get(Calendar.MONTH)]); result.append(MonthNameAbbrev[d.get(Calendar.MONTH)]);
break; break;
case 'B': case 'B':
@@ -256,22 +273,9 @@ public class OsLib extends TwoArgFunction {
case 'c': case 'c':
result.append(date("%a %b %d %H:%M:%S %Y", time)); result.append(date("%a %b %d %H:%M:%S %Y", time));
break; break;
case 'C':
result.append(String.valueOf((100000+d.get(Calendar.YEAR))/100).substring(2));
break;
case 'd': case 'd':
result.append(String.valueOf(100+d.get(Calendar.DAY_OF_MONTH)).substring(1)); result.append(String.valueOf(100+d.get(Calendar.DAY_OF_MONTH)).substring(1));
break; break;
case 'e': {
final String s = String.valueOf(d.get(Calendar.DAY_OF_MONTH));
if (s.length() < 2)
result.append((byte)' ');
result.append(s);
break;
}
case 'F':
result.append(date("%Y-%m-%d", time));
break;
case 'H': case 'H':
result.append(String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)).substring(1)); result.append(String.valueOf(100+d.get(Calendar.HOUR_OF_DAY)).substring(1));
break; break;
@@ -290,30 +294,12 @@ public class OsLib extends TwoArgFunction {
case 'M': case 'M':
result.append(String.valueOf(100+d.get(Calendar.MINUTE)).substring(1)); result.append(String.valueOf(100+d.get(Calendar.MINUTE)).substring(1));
break; break;
case 'n':
result.append((byte)'\n');
break;
case 'p': case 'p':
result.append(d.get(Calendar.HOUR_OF_DAY) < 12? "AM": "PM"); result.append(d.get(Calendar.HOUR_OF_DAY) < 12? "AM": "PM");
break; break;
case 'R':
result.append(date("%H:%M", time));
break;
case 'r': {
final String s = date("%I:%M:%S", time);
result.append(s);
result.append(d.get(Calendar.HOUR_OF_DAY) < 12? " am": " pm");
break;
}
case 'S': case 'S':
result.append(String.valueOf(100+d.get(Calendar.SECOND)).substring(1)); result.append(String.valueOf(100+d.get(Calendar.SECOND)).substring(1));
break; break;
case 't':
result.append((byte)'\t');
break;
case 'u':
result.append(String.valueOf((d.get(Calendar.DAY_OF_WEEK)+5)%7+1));
break;
case 'U': case 'U':
result.append(String.valueOf(weekNumber(d, 0))); result.append(String.valueOf(weekNumber(d, 0)));
break; break;
@@ -324,11 +310,9 @@ public class OsLib extends TwoArgFunction {
result.append(String.valueOf(weekNumber(d, 1))); result.append(String.valueOf(weekNumber(d, 1)));
break; break;
case 'x': case 'x':
case 'D':
result.append(date("%m/%d/%y", time)); result.append(date("%m/%d/%y", time));
break; break;
case 'X': case 'X':
case 'T':
result.append(date("%H:%M:%S", time)); result.append(date("%H:%M:%S", time));
break; break;
case 'y': case 'y':
@@ -338,12 +322,13 @@ public class OsLib extends TwoArgFunction {
result.append(String.valueOf(d.get(Calendar.YEAR))); result.append(String.valueOf(d.get(Calendar.YEAR)));
break; break;
case 'z': { case 'z': {
final int tzo = d.getTimeZone().getRawOffset() / (60 * 1000); final int tzo = timeZoneOffset(d) / 60;
result.append((tzo>0? "+": "") + String.valueOf(tzo)); final int a = Math.abs(tzo);
final String h = String.valueOf(100 + a / 60).substring(1);
final String m = String.valueOf(100 + a % 60).substring(1);
result.append((tzo>=0? "+": "-") + h + m);
break; break;
} }
case 'Z':
break;
} }
} }
} }
@@ -368,17 +353,33 @@ public class OsLib extends TwoArgFunction {
private int weekNumber(Calendar d, int startDay) { private int weekNumber(Calendar d, int startDay) {
Calendar y0 = beginningOfYear(d); Calendar y0 = beginningOfYear(d);
System.out.println("Time Date(time) " + d.getTime() + " y0 " + y0.getTime());
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7); y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
if (y0.after(d)) { if (y0.after(d)) {
y0.set(Calendar.YEAR, y0.get(Calendar.YEAR) - 1); y0.set(Calendar.YEAR, y0.get(Calendar.YEAR) - 1);
y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7); y0.set(Calendar.DAY_OF_MONTH, 1 + (startDay + 8 - y0.get(Calendar.DAY_OF_WEEK)) % 7);
System.out.println(" -> y0 " + y0.getTime());
} }
long dt = d.getTime().getTime() - y0.getTime().getTime(); long dt = d.getTime().getTime() - y0.getTime().getTime();
return 1 + (int) (dt / (7L * 24L * 3600L * 1000L)); return 1 + (int) (dt / (7L * 24L * 3600L * 1000L));
} }
private int timeZoneOffset(Calendar d) {
int localStandarTimeMillis = (
d.get(Calendar.HOUR_OF_DAY) * 3600 +
d.get(Calendar.MINUTE) * 60 +
d.get(Calendar.SECOND)) * 1000;
return d.getTimeZone().getOffset(
1,
d.get(Calendar.YEAR),
d.get(Calendar.MONTH),
d.get(Calendar.DAY_OF_MONTH),
d.get(Calendar.DAY_OF_WEEK),
localStandarTimeMillis) / 1000;
}
private boolean isDaylightSavingsTime(Calendar d) {
return timeZoneOffset(d) != d.getTimeZone().getRawOffset() / 1000;
}
/** /**
* This function is equivalent to the C function system. * This function is equivalent to the C function system.
* It passes command to be executed by an operating system shell. * It passes command to be executed by an operating system shell.

View File

@@ -25,37 +25,21 @@ public class OsLibTest extends TestCase {
public void testStringDate_b() { t("%b", "Aug"); } public void testStringDate_b() { t("%b", "Aug"); }
public void testStringDate_B() { t("%B", "August"); } public void testStringDate_B() { t("%B", "August"); }
public void testStringDate_c() { t("%c", "Thu Aug 23 14:55:02 2001"); } public void testStringDate_c() { t("%c", "Thu Aug 23 14:55:02 2001"); }
public void testStringDate_C() { t("%C", "20"); }
public void testStringDate_d() { t("%d", "23"); } public void testStringDate_d() { t("%d", "23"); }
public void testStringDate_D() { t("%D", "08/23/01"); }
public void testStringDate_e() { t("%e", "23"); }
public void testStringDate_F() { t("%F", "2001-08-23"); }
public void testStringDate_g() { t("%g", "%g"); } // not implemented.
public void testStringDate_G() { t("%G", "%G"); } // not implemented.
public void testStringDate_h() { t("%h", "Aug"); }
public void testStringDate_H() { t("%H", "14"); } public void testStringDate_H() { t("%H", "14"); }
public void testStringDate_I() { t("%I", "02"); } public void testStringDate_I() { t("%I", "02"); }
public void testStringDate_j() { t("%j", "235"); } public void testStringDate_j() { t("%j", "235"); }
public void testStringDate_m() { t("%m", "08"); } public void testStringDate_m() { t("%m", "08"); }
public void testStringDate_M() { t("%M", "55"); } public void testStringDate_M() { t("%M", "55"); }
public void testStringDate_n() { t("%n", "\n"); }
public void testStringDate_p() { t("%p", "PM"); } public void testStringDate_p() { t("%p", "PM"); }
public void testStringDate_r() { t("%r", "02:55:02 pm"); }
public void testStringDate_R() { t("%R", "14:55"); }
public void testStringDate_S() { t("%S", "02"); } public void testStringDate_S() { t("%S", "02"); }
public void testStringDate_t() { t("%t", "\t"); }
public void testStringDate_T() { t("%T", "14:55:02"); }
public void testStringDate_u() { t("%u", "4"); }
public void testStringDate_U() { t("%U", "33"); } public void testStringDate_U() { t("%U", "33"); }
public void testStringDate_V() { t("%V", "%V"); } // not implemented.
public void testStringDate_w() { t("%w", "4"); } public void testStringDate_w() { t("%w", "4"); }
public void testStringDate_W() { t("%W", "34"); } public void testStringDate_W() { t("%W", "34"); }
public void testStringDate_x() { t("%x", "08/23/01"); } public void testStringDate_x() { t("%x", "08/23/01"); }
public void testStringDate_X() { t("%X", "14:55:02"); } public void testStringDate_X() { t("%X", "14:55:02"); }
public void testStringDate_y() { t("%y", "01"); } public void testStringDate_y() { t("%y", "01"); }
public void testStringDate_Y() { t("%Y", "2001"); } public void testStringDate_Y() { t("%Y", "2001"); }
public void testStringDate_z() { t("%z", "-480"); }
public void testStringDate_Z() { t("%Z", ""); }
public void testStringDate_Pct() { t("%%", "%"); } public void testStringDate_Pct() { t("%%", "%"); }
static final double DAY = 24. * 3600.; static final double DAY = 24. * 3600.;

Binary file not shown.

View File

@@ -37,3 +37,20 @@ print( 'os.remove(q)', pcall( os.remove, q ) )
-- print( 'os.setlocale(nil,"all")', pcall( os.setlocale, nil, "all" ) ) -- print( 'os.setlocale(nil,"all")', pcall( os.setlocale, nil, "all" ) )
print( 'os.setlocale("C")', pcall( os.setlocale, "C" ) ) print( 'os.setlocale("C")', pcall( os.setlocale, "C" ) )
print( 'os.exit', type(os.exit) ) print( 'os.exit', type(os.exit) )
-- os.date() formatting
local t = 1281364496 -- Aug 9, 2010, 2:34:56 PM (Monday)
local function p(s)
if pcall(os.date, s, t) then
print( "os.date('"..s.."', "..t..")", pcall(os.date, s, t))
end
end
for i= 65, 90 do
p('%'..string.char(i + 97 - 65))
p('%'..string.char(i))
end
local tbl = os.date('*t', t)
for i,k in ipairs({'year', 'month', 'day', 'hour', 'min', 'sec', 'wday', 'yday', 'isdst'}) do
local v = tbl[k]
print('k', type(k), k, 'v', type(v), v)
end