java - example - simpledateformat to date
Android parse String to Date-carácter de patrón desconocido ''X'' (11)
Tengo la cadena de fecha de recuperación del servicio desde la web y luego quiero emparejarlo con el objeto Date
. Pero de alguna manera falla la aplicación. Esta es la cadena que estoy analizando: 2015-02-05T05:20:02+00:00
onStartCommand ()
String datetime = "2015-02-05T05:20:02+00:00";
Date new_date = stringToDate(datetime);
stringToDate ()
private Date stringToDate(String s){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssXXX");
try{
return df.parse(s);
}catch(ParseException e){
e.printStackTrace();
}
return null;
}
LogCat:
02-06 20:37:02.008: E/AndroidRuntime(28565): FATAL EXCEPTION: main
02-06 20:37:02.008: E/AndroidRuntime(28565): Process: com.dotmav.runescapenotifier, PID: 28565
02-06 20:37:02.008: E/AndroidRuntime(28565): java.lang.RuntimeException: Unable to start service com.dotmav.runescapenotifier.GEService@384655b5 with Intent { cmp=com.dotmav.runescapenotifier/.GEService }: java.lang.IllegalArgumentException: Unknown pattern character ''X''
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2881)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.app.ActivityThread.access$2100(ActivityThread.java:144)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1376)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.os.Handler.dispatchMessage(Handler.java:102)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.os.Looper.loop(Looper.java:135)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.app.ActivityThread.main(ActivityThread.java:5221)
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.lang.reflect.Method.invoke(Native Method)
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.lang.reflect.Method.invoke(Method.java:372)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
02-06 20:37:02.008: E/AndroidRuntime(28565): Caused by: java.lang.IllegalArgumentException: Unknown pattern character ''X''
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.text.SimpleDateFormat.validatePatternCharacter(SimpleDateFormat.java:314)
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.text.SimpleDateFormat.validatePattern(SimpleDateFormat.java:303)
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:356)
02-06 20:37:02.008: E/AndroidRuntime(28565): at java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:249)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.dotmav.runescapenotifier.GEService.stringToDate(GEService.java:68)
02-06 20:37:02.008: E/AndroidRuntime(28565): at com.dotmav.runescapenotifier.GEService.onStartCommand(GEService.java:44)
02-06 20:37:02.008: E/AndroidRuntime(28565): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2864)
02-06 20:37:02.008: E/AndroidRuntime(28565): ... 9 more
EDIT: onDestroy () configura la alarma para la actualización periódica ...
AlarmManager alarm = (AlarmManager)getSystemService(ALARM_SERVICE);
alarm.set(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + (1000 * 60),
PendingIntent.getService(this, 0, new Intent(this, GEService.class), 0)
);
tl; dr
long millisecondsSinceEpoch = OffsetDateTime.parse( "2015-02-05T05:20:02+00:00" ).plusHour( 1 ).toInstant().toEpochMilli() // Warning: Possible loss of data in truncating nanoseconds to milliseconds. But not in this particular case.
Detalles
Otras respuestas son correctas pero ahora están desactualizadas. Las antiguas clases de fecha y hora ahora son heredadas. Use clases java.time en su lugar.
ISO 8601
La cadena de entrada está en formato estándar ISO 8601. Parse directamente, no es necesario definir un patrón de formateo ya que las clases java.time usan formatos ISO 8601 de forma predeterminada.
OffsetDateTime
La entrada incluye un offset-from-UTC con el +00:00
por lo que podemos analizar como un objeto OffsetDateTime
.
String input = "2015-02-05T05:20:02+00:00" ;
OffsetDateTime odt = OffsetDateTime.parse( input );
Mates
Si desea agregar una hora o un minuto más tarde para configurar una alarma, llame a los métodos plus
.
OffsetDateTime minuteLater = odt.plusMinutes( 1 );
OffsetDateTime hourLater = odt.plusHours( 1 );
Para obtener una cuenta de milisegundos, vaya a la clase Instant
. La clase Instant
representa un momento en la línea de tiempo en UTC con una resolución de nanoseconds . Pedir milisegundos significa la pérdida de datos posible ya que los nueve dígitos de una fracción decimal se truncan a los tres dígitos de la fracción decimal.
long millisecondsSinceEpoch = odt.toInstant().toEpochMilli(); // Warning: Possible loss of data in truncating nanoseconds to milliseconds.
Acerca de java.time
El marco java.time está integrado en Java 8 y posterior. Estas clases suplantan a las antiguas clases problemáticas de fecha y hora, como java.util.Date
, .Calendar
y java.text.SimpleDateFormat
.
El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a java.time.
Para obtener más información, consulte el Tutorial de Oracle . Y busque para obtener muchos ejemplos y explicaciones.
Gran parte de la funcionalidad de java.time se transfiere a Java 6 y 7 en ThreeTen-Backport y se adapta aún más a Android en ThreeTenABP .
El proyecto ThreeTen-Extra amplía java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time.
Android developer.android.com/reference/java/text/SimpleDateFormat.html es diferente de Java 7 SDK y no admite ''X'' para analizar ISO 8601. Puede usar los estilos ''Z'' o ''ZZZZZ'' para formatear y establecer programáticamente la zona horaria en UTC. Aquí hay una clase util:
public class DateUtil {
public static final String iso8601DatePattern = "yyyy-MM-dd''T''HH:mm:ss.SSSZZZZZ";
public static final DateFormat iso8601DateFormat = new SimpleDateFormat(iso8601DatePattern);
public static final TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
static {
iso8601DateFormat.setTimeZone(utcTimeZone);
}
public static String formatAsIso8601(Date date) {
return iso8601DateFormat.format(date);
}
}
Como Z y XXX son diferentes, he implementado la siguiente solución alternativa:
// This is a workaround from Z to XXX timezone format
new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ") {
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) {
StringBuffer rfcFormat = super.format(date, toAppendTo, pos);
return rfcFormat.insert(rfcFormat.length() - 2, ":");
}
@Override
public Date parse(String text, ParsePosition pos) {
if (text.length() > 3) {
text = text.substring(0, text.length() - 3) + text.substring(text.length() - 2);
}
return super.parse(text, pos);
}
}
El error es decir que simpleDateFormat no reconoce el carácter X. Si está buscando milisegundos, se representa con el carácter S.
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSSZ");
Eliminar "XXX" de
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssXXX");
y todo funcionaria bien
SimpleDateFormat
la lista de símbolos que se pueden usar dentro de un constructor SimpleDateFormat
. Esta es la developer.android.com/reference/java/text/SimpleDateFormat.html
Probablemente estás buscando "yyyy-MM-dd''T''HH:mm:ss.SSSZ"
Cambia tu código a
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSS");
o
DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssZ"); // if timezone is required
Está utilizando el formateador de fecha incorrecto.
Use esto en su lugar: DateFormat df = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ssZ");
Creo que Android, en contraste con Java 7 usa Z (como en Java 6) para zonas horarias y no X. Por lo tanto, use developer.android.com/reference/java/text/SimpleDateFormat.html para sus formatos de fecha.
La siguiente clase se puede usar para convertir la cadena a la fecha cuando el patrón no la conoce.
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* StringToDateFormater is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for
* formatting (date → text), parsing (text → date), and normalization.
*
* This class is mainly used for convert the date from string. It should be used only when date pattern doesn''t aware of
* it.
*
*/
public class StringToDateFormater extends SimpleDateFormat {
private static final List<String> DATE_SUPPORTED_FORMAT_LIST = Arrays.asList("yyyyMMddHHmmss", "yyyyMMddHHmm",
"yyyyMMddHHmm", "yyyyMMddHH", "yyyyMMdd", "yyyyMMddHHmmssSS");
/**
*
*/
private static final long serialVersionUID = -1732857502488169225L;
/**
* @param pattern
*/
public StringToDateFormater() {
}
@Override
public Date parse(String source) {
Date date = null;
SimpleDateFormat dateFormat = null;
for (String format : DATE_SUPPORTED_FORMAT_LIST) {
dateFormat = new SimpleDateFormat(format);
try {
return dateFormat.parse(source);
} catch (Exception exception) {
}
}
return date;
}
}
La versión Android de SimpleDateFormat
no admite el patrón X
, por lo que XXX
no funcionará, pero en su lugar puede usar ZZZZZ
que hace lo mismo y genera la zona horaria en formato +02:00
(o -02:00
dependiendo de la zona horaria local) .
Nadie mencionó que este error ocurriera en los dispositivos de pre turrón, así que pensé en compartir mi respuesta y tal vez sea útil para aquellos que llegaron a este hilo debido a eso.
Esta answer correctamente menciona que "X" solo es compatible con los dispositivos Nougat +. Sigo viendo que la documentation sugiere usar "yyyy-MM-dd''T''HH:mm:ss.SSSXXX"
y no estoy seguro de por qué no hacen explícito este punto.
Para mí, yyyy-MM-dd''T''HH:mm:ssXXX
funcionaba bien hasta que intenté probarlo en el dispositivo 6.0 y comenzó a fallar, lo que me llevó a investigar sobre este tema. Sustituirlo por yyyy-MM-dd''T''HH:mm:ss.SSSZZZZZ
ha resuelto el problema y funciona en todos los dispositivos 5.0+.
Solución simple:
Usa este yyyy-MM-dd''T''HH:mm:ss.SSSZZZZZ
En lugar de yyyy-MM-dd''T''HH:mm:ss.SSSXXX
Hecho.
Use un SimpleDateFormat
para producir un resultado de String
con String
formato SimpleDateFormat
:
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd''T''HH:mm:ss.SSS''Z''");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String formattedNow = simpleDateFormat.format(new Date(System.currentTimeMillis()));
Salida: 2018-02-27T07:36:47.686Z