TransWikia.com

Retornar dia da semana a partir de uma data no formato dd/mm/yyy

Stack Overflow em Português Asked by Rafael Silva on November 30, 2021

tenho essa função que me traz o dia da semana:

public static String getWeek(String date){ //ex 07/03/2017
    String dayWeek = "---";
    GregorianCalendar gc = new GregorianCalendar();
    try {
        gc.setTime(new SimpleDateFormat("MM/dd/yyyy", BRAZIL).parse(date));
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case Calendar.SUNDAY:
                dayWeek = "DOM";
                break;
            case Calendar.MONDAY:
                dayWeek = "SEG";
                break;
            case Calendar.TUESDAY:
                dayWeek = "TER";
            break;
            case Calendar.WEDNESDAY:
                dayWeek = "QUA";
                break;
            case Calendar.THURSDAY:
                dayWeek = "QUI";
                break;
            case Calendar.FRIDAY:
                dayWeek = "SEX";
                break;
            case Calendar.SATURDAY:
                dayWeek = "SAB";

        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return dayWeek;
}

Mas ela esta me trazendo o dia da semana anterior, ex: 07/03/2017 terça-feira ele traz como segunda-feira.

4 Answers

A partir do Java 8, você pode usar a API java.time

import java.time.DayOfWeek;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Locale;

public static String getDayOfWeek(String data) {
    DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu");
    DayOfWeek dow = DayOfWeek.from(parser.parse(data));
    return dow.getDisplayName(TextStyle.SHORT, new Locale("pt", "BR")).toUpperCase();
}

System.out.println(getDayOfWeek("07/03/2017")); // TER

Eu também poderia fazer LocalDate.parse(data, parser).getDayOfWeek() para obter o DayOfWeeek, mas se você só quer o dia da semana, não precisa criar um LocalDate à toa.

E mudei o nome do método, pois getWeek dá a impressão de que vai retornar toda a semana, mas você só quer um dia da semana, então deixei como getDayOfWeek.


Outro detalhe é que no seu método você está capturando a exceção (ParseException caso a data seja inválida), imprimindo o stack trace e depois retornando "---". Sem entrar no mérito de não estar tratando o erro, uma forma de ter o mesmo comportamento é:

public static String getDayOfWeek(String data) {
    try {
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("dd/MM/uuuu")
                                      .withResolverStyle(ResolverStyle.STRICT);
        DayOfWeek dow = DayOfWeek.from(parser.parse(data));
        return dow.getDisplayName(TextStyle.SHORT, new Locale("pt", "BR")).toUpperCase();
    } catch (DateTimeException e) {
        e.printStackTrace();
    }
    return "---";
}

System.out.println(getDayOfWeek("31/02/2017")); // ---

O ResolverStyle, conforme explicado aqui, serve para garantir que datas como 29 de fevereiro em anos não-bissextos e 31 de abril sejam consideradas inválidas - tem uma explicação mais detalhada nesta resposta, na seção "Modos de parsing".


Mas este método não é muito eficiente, pois toda vez que for chamado, cria duas instâncias de DateTimeFormatter: uma explicitamente, e outra implicitamente, dentro de getDisplayName (veja no código fonte).

Sendo assim, uma alternativa é guardar essas instâncias em variáveis estáticas, assim eles são criados apenas uma vez:

public static DateTimeFormatter DOW_FMT = DateTimeFormatter.ofPattern("E", new Locale("pt", "BR"));

public static DateTimeFormatter PARSER = DateTimeFormatter.ofPattern("dd/MM/uuuu").withResolverStyle(ResolverStyle.STRICT);

public static String getDayOfWeek(String data) {
    try {
        return DOW_FMT.format(PARSER.parse(data)).toUpperCase();
    } catch (DateTimeException e) {
        e.printStackTrace();
    }
    return "---";
}

Repare que assim você nem precisa criar o DayOfWeek, pois o resultado do parsing é passado diretamente para o formatador, que já pega o dia da semana e formata.


Se quiser continuar usando SimpleDateFormat, há um detalhe importante: por padrão, esta classe aceita datas inválidas como "33/22/2017", fazendo alguns ajustes bem estranhos:

// 33/22/2017 vira 2 de novembro de 2018
System.out.println(new SimpleDateFormat("dd/MM/yyyy").parse("33/22/2017")); // Fri Nov 02 00:00:00 BRT 2018

Para evitar esse problema, basta setá-lo como não-leniente:

public static String getWeek(String date) { // ex 07/03/2017
    String dayWeek = "---";
    GregorianCalendar gc = new GregorianCalendar();
    SimpleDateFormat parser = new SimpleDateFormat("dd/MM/yyyy");
    parser.setLenient(false); // <- setar como não-leniente, assim não aceita datas inválidas
    try {
        gc.setTime(parser.parse(date));
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            etc...

Uma outra resposta sugeriu usar DateFormatSymbols, mas foi usado getWeekdays, que retorna os nomes completos ("Domingo", "Segunda-feira", etc). Sem contar que se você criá-la sem especificar um Locale, como foi sugerido, ela usará o default que está configurado na JVM (por exemplo, se a JVM estiver configurada com algum locale em inglês, serão retornados os nomes neste idioma - "Sunday", "Monday", etc).

Então se quiser usar aquela solução, você precisa especificar o locale para que use o português, e usar getShortWeekdays para ter os nomes abreviados. E como esse array é fixo e será usado sempre que o método for chamado, pode criá-lo apenas uma vez também:

public static String[] WEEKDAYS = new DateFormatSymbols(new Locale("pt", "BR")).getShortWeekdays();

public static String getDayOfWeek(String data) {
    try {
        SimpleDateFormat parser = new SimpleDateFormat("dd/MM/yyyy");
        parser.setLenient(false);
        Calendar cal = Calendar.getInstance();
        cal.setTime(parser.parse(data));
        return WEEKDAYS[cal.get(Calendar.DAY_OF_WEEK)].toUpperCase();
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return "---";
}

Ou, se quiser otimizar mais ainda, já deixe o array com os nomes em maiúsculas, assim você não precisa chamar toUpperCase:

public static String[] WEEKDAYS;
static {
    WEEKDAYS = new DateFormatSymbols(new Locale("pt", "BR")).getShortWeekdays();
    for (int i = 0; i < WEEKDAYS.length; i++) {
        WEEKDAYS[i] = WEEKDAYS[i].toUpperCase();
    }
}

public static String getDayOfWeek(String data) {
    try {
        SimpleDateFormat parser = new SimpleDateFormat("dd/MM/yyyy");
        parser.setLenient(false);
        Calendar cal = Calendar.getInstance();
        cal.setTime(parser.parse(data));
        return WEEKDAYS[cal.get(Calendar.DAY_OF_WEEK)];
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return "---";
}

E claro que também tem a opção de usar um array com os valores fixos:

public static String[] WEEKDAYS = {"DOM", "SEG", "TER", "QUA", "QUI", "SEX", "SAB"};

public static String getDayOfWeek(String data) {
    try {
        SimpleDateFormat parser = new SimpleDateFormat("dd/MM/yyyy");
        parser.setLenient(false);
        Calendar cal = Calendar.getInstance();
        cal.setTime(parser.parse(data));
        return WEEKDAYS[cal.get(Calendar.DAY_OF_WEEK) - 1];
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return "---";
}

O detalhe é que arrays começam do índice zero, mas os valores de DAY_OF_WEEK vão de 1 a 7 (Domingo a Sábado), então preciso subtrair 1 para obter o valor correto (no caso de getShortWeekdays não é necessário porque ele retorna um array cuja primeira posição é uma string vazia).

Answered by hkotsubo on November 30, 2021

Costumo usar o componente DateChooser na interface. O componente DateChooser retorna um java.util.Calendar. Com isso, você poderá usar métodos como estes:

public String diaDaSemana(Calendar calendar) {
    return new DateFormatSymbols().getWeekdays()[calendar.get(Calendar.DAY_OF_WEEK)];
}

public String nomeDoMes(Calendar calendar) {
    return new DateFormatSymbols().getMonths()[calendar.get(Calendar.MONTH)];
}

Answered by Hilton Cesar on November 30, 2021

A sua máscara está errada, como o Articuno respondeu.

Você também pode encurtar o seu código para:

public static String getWeek(String date){ //ex 07/03/2017
        String dayWeek = "---";
        GregorianCalendar gc = new GregorianCalendar();
        try {
            gc.setTime(new SimpleDateFormat("dd/MM/yyyy", new Locale("pt", "BR")).parse(date));
           return new SimpleDateFormat("EEE", new Locale("pt", "BR")).format(gc.getTime()).toUpperCase();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return dayWeek;
    }

Answered by mari on November 30, 2021

Sua máscara de formatação de data está errada. Você está usando o formato MM/dd/yyyy quando sua string recebe um formato dd/MM/yyyy. Apenas altere a máscara:

public static String getWeek(String date){ //ex 07/03/2017
    String dayWeek = "---";
    GregorianCalendar gc = new GregorianCalendar();
    try {
        gc.setTime(new SimpleDateFormat("dd/MM/yyyy").parse(date));
        switch (gc.get(Calendar.DAY_OF_WEEK)) {
            case Calendar.SUNDAY:
                dayWeek = "DOM";
                break;
            case Calendar.MONDAY:
                dayWeek = "SEG";
                break;
            case Calendar.TUESDAY:
                dayWeek = "TER";
            break;
            case Calendar.WEDNESDAY:
                dayWeek = "QUA";
                break;
            case Calendar.THURSDAY:
                dayWeek = "QUI";
                break;
            case Calendar.FRIDAY:
                dayWeek = "SEX";
                break;
            case Calendar.SATURDAY:
                dayWeek = "SAB";

        }
    } catch (ParseException e) {
        e.printStackTrace();
    }
    return dayWeek;
}

Bastou esta alteração e funcionou corretamente, veja: https://ideone.com/LLcvyr

Answered by user28595 on November 30, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP