Jak przekonwertować currentTimeMillis na datę w Javie?

140

Mam milisekundy w pewnym pliku dziennika wygenerowanym na serwerze, znam również lokalizację, z której został wygenerowany plik dziennika, moim problemem jest konwersja milisekund do daty w określonym formacie. Przetwarzanie tego dziennika odbywa się na serwerze znajdującym się w innej strefie czasowej. Podczas konwersji do formatu „SimpleDateFormat” program pobiera datę maszyny, ponieważ taka sformatowana data nie reprezentuje prawidłowego czasu serwera. Czy jest jakiś sposób, aby poradzić sobie z tym elegancko?

long yourmilliseconds = 1322018752992l;
        //1322018752992-Nov 22, 2011 9:25:52 PM 

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS",Locale.US);

GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("US/Central"));
calendar.setTimeInMillis(yourmilliseconds);

System.out.println("GregorianCalendar -"+sdf.format(calendar.getTime()));

DateTime jodaTime = new DateTime(yourmilliseconds, 
                    DateTimeZone.forTimeZone(TimeZone.getTimeZone("US/Central")));
DateTimeFormatter parser1 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss,SSS");

System.out.println("jodaTime "+parser1.print(jodaTime));

Wynik:

Gregorian Calendar -2011-11-23 08:55:52,992
jodaTime 2011-11-22 21:25:52,992
Amit
źródło
Nie myl ustawienia Locale ze strefą czasową. Całkowicie oddzielne. Ustawienia regionalne określają język ludzi na podstawie nazw miesięcy i dni oraz norm kulturowych, takich jak kolejność części, takich jak miesiąc, dzień itp. Strefa czasowa jest przesunięta w stosunku do czasu UTC plus zasady obsługi anomalii, takich jak czas letni.
Basil Bourque,
Czy problem polegał na tym, że liczba milisekund była liczbą nie od 1970-01-01T00: 00: 00Z, ale od innego momentu?
Basil Bourque,
FYI, zarówno straszne stare klas date-time ( GregorianCalendar, SimpleDateFormatetc.) oraz doskonałe biblioteki Joda-Time są obecnie wypierane przez nowoczesne java.time klas.
Basil Bourque

Odpowiedzi:

115
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeStamp);

int mYear = calendar.get(Calendar.YEAR);
int mMonth = calendar.get(Calendar.MONTH);
int mDay = calendar.get(Calendar.DAY_OF_MONTH);
Faisal Ashraf
źródło
Musiałem ustawić Kalendarz jako ostateczny, aby działał. final Calendar calendar = Calendar.getInstance();
Victor Augusto
4
Obiekty kalendarza są ogólnie uważane za dość duże, więc należy ich unikać, gdy jest to możliwe. Obiekt Date będzie lepszy, zakładając, że ma potrzebną funkcjonalność. "Data data = nowa data (milis);" podana w innej odpowiedzi przez użytkownika AVD będzie najlepszą trasą :)
Dick Lucas
1
Jakoś, 1515436200000lbo dostaję się calendar.get(Calendar.MONTH))jak 0!
Sajib Acharya,
FYI, strasznie kłopotliwe stare klasy daty i godziny, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz starsze , zastąpione przez klasy java.time wbudowane w Javę 8 i nowsze. Zobacz samouczek firmy Oracle .
Basil Bourque,
2
@SajibAcharya Zwróć uwagę, że wystąpienia Calendar.MONTH zaczynają się od 0; musisz dodać jeden, aby otrzymać „prawdziwy” miesiąc, jaki znamy. Przykład: 0 = styczeń, 1 = luty, 2 = marzec itd.
shagberg,
256

Możesz użyć java.util.Dateclass, a następnie użyć SimpleDateFormatdo sformatowania pliku Date.

Date date=new Date(millis);

Możemy wykorzystać pakiet java.time (tutorial) - API DateTime wprowadzone w Javie SE 8.

var instance = java.time.Instant.ofEpochMilli(millis);
var localDateTime = java.time.LocalDateTime
                        .ofInstant(instance, java.time.ZoneId.of("Asia/Kolkata"));
var zonedDateTime = java.time.ZonedDateTime
                            .ofInstant(instance,java.time.ZoneId.of("Asia/Kolkata"));

// Format the date

var formatter = java.time.format.DateTimeFormatter.ofPattern("u-M-d hh:mm:ss a O");
var string = zonedDateTime.format(formatter);
adatapost
źródło
2
Dużo bardziej wydajne.
Chad Bingham
2
Nie. Nie wszystkie metody java.util.Datesą amortyzowane. (W JDK8 są ulepszone API daty i czasu java.time)
adatapost
1
@RafaelZeffa, konstruktor '' 'Date (long date)' '' nie jest przestarzały
Gugelhupf
Obiekt Date zapewnia zgodność z poprzednimi wersjami. Lepiej korzystaj z Kalendarza zgodnie z powyższą sugestią.
Ton Snoei
2
FYI, strasznie kłopotliwe stare klasy daty i godziny, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz starsze , zastąpione przez klasy java.time wbudowane w Javę 8 i nowsze. Zobacz samouczek firmy Oracle .
Basil Bourque,
24

tl; dr

Instant.ofEpochMilli( 1_322_018_752_992L )     // Parse count of milliseconds-since-start-of-1970-UTC into an `Instant`.
       .atZone( ZoneId.of( "Africa/Tunis" ) )  // Assign a time zone to the `Instant` to produce a `ZonedDateTime` object.

Detale

Inne odpowiedzi używają przestarzałych lub niepoprawnych klas.

Unikaj starych klas daty i godziny, takich jak java.util.Date/.Calendar. Okazały się źle zaprojektowane, zagmatwane i kłopotliwe.

java.time

Java.time ramy przychodzi wbudowany w Java 8 i późniejszych. Wiele funkcji zostało przeniesionych do Java 6 i 7 i dodatkowo dostosowanych do systemu Android . Wykonane przez tych samych ludzi, którzy stworzyli Joda-Time .

Jest Instantmoment na osi czasu w UTC z rozdzielczością nanosekund . Jego epoka to pierwszy moment 1970 roku w UTC.

Zakładając, że dane wejściowe są liczbą milisekund od 1970-01-01T00: 00: 00Z (nie jest jasne w pytaniu), możemy łatwo utworzyć instancję Instant.

Instant instant = Instant.ofEpochMilli( 1_322_018_752_992L );

instant.toString (): 2011-11-23T03: 25: 52.992Z

W Ztym standardzie ciąg w formacie ISO 8601 jest skrótem od Zului oznacza UTC .

Zastosuj strefę czasową, używając odpowiedniej nazwy strefy czasowej , aby uzyskać ZonedDateTime.

ZoneId zoneId = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( zoneId );

Zobacz, jak działa ten kod na IdeOne.com .

Asia/Kolkata strefa czasowa ?

Domyślam się, że strefa czasowa Indii wpływa na Twój kod. Widzimy tutaj, że dostosowanie do Asia/Kolkatastrefy czasowej powoduje renderowanie tej samej pory dnia, co zgłaszasz, 08:55czyli pięć i pół godziny przed naszą wartością UTC 03:25.

2011-11-23T08: 55: 52.992 + 05: 30 [Azja / Kalkuta]

Strefa domyślna

Możesz zastosować bieżącą domyślną strefę czasową maszyny JVM. Pamiętaj, że wartość domyślna może się zmienić w dowolnym momencie podczas działania . Dowolny kod w dowolnym wątku dowolnej aplikacji w JVM może zmienić bieżącą wartość domyślną. Jeśli to ważne, zapytaj użytkownika o żądaną / oczekiwaną strefę czasową.

ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Korzystając ze sterownika JDBC zgodnego z JDBC 4.2 lub nowszym, możesz wymieniać obiekty java.time bezpośrednio z bazą danych. Nie ma potrzeby używania ciągów znaków ani klas java.sql. *.

Skąd wziąć klasy java.time?

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
Czy łatwo byłoby przekonwertować zalecane powyżej wyszukiwanie błyskawiczne na lokalną strefę czasową, która jest domyślna na urządzeniu (na przykład smartfonie)?
AJW
1
@AJW Yes. Zadzwoń ZoneId.systemDefault(). Zobacz nową sekcję dodaną na końcu mojej odpowiedzi.
Basil Bourque
Świetnie, spróbuję.
AJW
14

Najłatwiej to zrobić, używając klasy Joda DateTime i określając zarówno znacznik czasu w milisekundach, jak i żądaną strefę DateTimeZone.

Zdecydowanie zalecam unikanie wbudowanych klas Java Date i Calendar; są okropne.

Cameron Skinner
źródło
GorgianCalender nie działał ... z jakiegoś powodu wymagał domyślnej strefy czasowej systemu. Joda działała doskonale.
Amit
Daj mi znać, patrząc na przykładowy kod, czy możemy zrobić coś innego z Gregorianem
Amit
1
FYI, projekt Joda-Time jest teraz w trybie konserwacji i zaleca migrację do klas java.time . Zobacz samouczek firmy Oracle .
Basil Bourque,
13

Jeśli wartość milis jest liczbą milis od 1 stycznia 1970 GMT, co jest standardem dla maszyny JVM, to jest to niezależne od strefy czasowej. Jeśli chcesz sformatować go przy użyciu określonej strefy czasowej, możesz po prostu przekonwertować go na obiekt GregorianCalendar i ustawić strefę czasową. Następnie istnieje wiele sposobów na sformatowanie go.

Rachunek
źródło
1
To jest przykładowy kod z GregorianCalendar i Joda. Otrzymuję poprawne dane wyjściowe z Joda, ale nie z Gregorian GregorianCalendar calendar = new GregorianCalendar (TimeZone.getTimeZone ("US / Central")); calendar.setTimeInMillis (yourmilliseconds); DateTime jodaTime = new DateTime (yourmilliseconds, DateTimeZone.forTimeZone (TimeZone.getTimeZone ("USA / Central"))); DateTimeFormatter parser1 = DateTimeFormat.forPattern ("rrrr-MM-dd HH: mm: ss, SSS");
Amit
Ustawienie strefy czasowej w obiekcie kalendarza nie zadziałało, ale ustawienie jej w obiekcie formatowania daty zadziałało?
Bill
Co to jest DateTime i DateTimeFormatter?
SweetWisher ツ
11

Moje rozwiązanie

public class CalendarUtils {

    public static String dateFormat = "dd-MM-yyyy hh:mm";
    private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat);

    public static String ConvertMilliSecondsToFormattedDate(String milliSeconds){
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(Long.parseLong(milliSeconds));
        return simpleDateFormat.format(calendar.getTime());
    }
}
Siddarth Kanted
źródło
6

Robię to tak:

static String formatDate(long dateInMillis) {
    Date date = new Date(dateInMillis);
    return DateFormat.getDateInstance().format(date);
}

Możesz również użyć getDateInstance(int style)następujących parametrów:

DateFormat.SHORT

DateFormat.MEDIUM

DateFormat.LONG

DateFormat.FULL

DateFormat.DEFAULT

Yogesh Umesh Vaity
źródło
5

Klasa SimpleDateFormat zawiera metodę o nazwie SetTimeZone (TimeZone), która jest dziedziczona z klasy DateFormat. http://docs.oracle.com/javase/6/docs/api/java/text/DateFormat.html

Jessica Brown
źródło
FYI, te okropne klasy są teraz zastępowane przez nowoczesne klasy java.time od przyjęcia JSR 310.
Basil Bourque
5

Najprostszy sposób:

private String millisToDate(long millis){

    return DateFormat.getDateInstance(DateFormat.SHORT).format(millis);
    //You can use DateFormat.LONG instead of SHORT

}
Joaquin Iurchuk
źródło
2

Poniżej znajduje się moje rozwiązanie, aby uzyskać datę z milisekund do formatu daty. Aby uruchomić ten kod, musisz użyć Joda Library .

import java.util.GregorianCalendar;
import java.util.TimeZone;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class time {

    public static void main(String args[]){

        String str = "1431601084000";
        long geTime= Long.parseLong(str);
        GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("US/Central"));
        calendar.setTimeInMillis(geTime);
        DateTime jodaTime = new DateTime(geTime, 
               DateTimeZone.forTimeZone(TimeZone.getTimeZone("US/Central")));
        DateTimeFormatter parser1 = DateTimeFormat.forPattern("yyyy-MM-dd");
        System.out.println("Get Time : "+parser1.print(jodaTime));

   }
}
Archit
źródło
1

Możesz spróbować java.time api;

        Instant date = Instant.ofEpochMilli(1549362600000l);
        LocalDateTime utc = LocalDateTime.ofInstant(date, ZoneOffset.UTC);
Narendar Reddy M
źródło