달달한 스토리

728x90
반응형

오늘도 열정적으로 개발하는 자팍이입니다.

 

오늘 배웠던 이 타이머는 어디서도 구하지 못해..

 

직접 물어보고, 한참을 보다가

 

구현해낸 누군가에겐 별거 아니지만,

 

저에게는 값진 발견입니다.. 헤헤

 

금연 타이머 앱을 만들던 중..

 

어떻게 하면, 입력한 시간과 날짜대로,

 

시간이 입력될까?

 

라는 생각이 들었습니다.

 

커뮤니티에 물어보니, 날짜나 시간을 계산하고, 그것을

 

초(밀리세컨드)로 변환하면, 그것이 가능하다고 했습니다.

 

하지만 처음에는 도저히 이해가 되지 않았습니다.

 

우선 예제를 보여드리겠습니다.

 

이 기능을 사용하시지 않더라도, 

 

예제에 포함된 Calculate_Date.java안에

 

날짜 차이 구하기, 시간 차이 구하기, 현재 날짜와 시간 나타내는

 

메서드가 있으므로, 잘 활용하시길 바랍니다.

 


코드들

MainActivity.java

 

public class MainActivity extends AppCompatActivity {

    private Thread timeThread = null;
    private final Boolean isRunning = true;

    private TextView textTime, textDate;

    private Button checkBtn;

    private long finallyDate;
    private long finallyTime;

    private Calculate_Date calculate_date;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        checkBtn = findViewById(R.id.checkBtn); //시간 계산


        calculate_date = new Calculate_Date(); //Calculate_Date 객체 만들기

        textDate = findViewById(R.id.textView_date); //날짜결과 나타내는 텍스트뷰
        textTime = findViewById(R.id.textView_time); //시간결과 나타내는 텍스트뷰

        checkBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String timeNow = calculate_date.WhatTimeIsItTime(); //현재 시간
                String myTime = "12:30:00";// 지정한 시간 //HH:mm:ss 형식으로 적어줘야한다.(원하면 Calculate_Date)에서 수정가능.

                String dateNow = calculate_date.WhatTimeIsItDate(); //현재 날짜
                String myDate = "2021-01-12"; //지정한 날짜 //yyyy-MM-dd 형식 수정가능


                try {
                    finallyTime = calculate_date.calTimeBetweenAandB(myTime, timeNow); //첫번째 인자는 지정한 시간이고, 두번 째는 현재시간이다.

                    finallyDate = calculate_date.calDateBetweenAandB(myDate, dateNow); //첫번째 인자는 지정한 날짜이고, 두번 째는 현재날짜이다.
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                timeThread = new Thread(new timeThread());
                timeThread.start();
            }
        });



    }

    Handler handler = new Handler(Looper.myLooper()) { //실시간 날짜를 출력해주는 핸들러
        @Override
        public void handleMessage(Message msg) {

            //(msg.arg1 / 100) 이 1초이다. 1초는 1000단위이므로,
            //int min = (msg.arg1 / 100) / 60 같은 경우는 1/60이니까 분이다. (시간도 마찬가지)
            int sec = (msg.arg1 / 100) % 60; //초
            int min = (msg.arg1 / 100) / 60 % 60; //분
            int hour = (msg.arg1 / 100) / 3600 % 24; //시
            int day = (msg.arg2 / 100) / 86400; //하루

            String result = String.format("%02d:%02d:%02d", hour, min, sec);
            Log.d("리절트", result);

            String oneDay = String.format("%d", day);
            Log.d("원데이", oneDay);

            /** result 실시간 시간초이다.*/
            textTime.setText("오늘을 기준으로\n\n" + result + "버틴 시간"); //시간표시
            textDate.setText("오늘 기준으로" + oneDay + "일 지났습니다."); //날짜표시
        }
    };




    public class timeThread implements Runnable {
        //타이머 쓰레드
        @Override
        public void run() {
            int i = (int) finallyTime; //여기에 몇 초인지 넣어야 그 때부터 타이머가 시작된다.
            int day = (int) finallyDate; //여기에는 날짜를 넣는데, 마찬가지로 초 형식으로 넣는다.
            Log.d("뭐야", String.valueOf(i));
            while (true) {
                while (isRunning) { //일시정지를 누르면 멈춤
                    Message msg = new Message();
                    msg.arg1 = i++;
                    msg.arg2 = day++;
                    handler.sendMessage(msg); //인자 넣기(
                    try {
                        Thread.sleep(10); //혹시나 멈췄을 경우를 대비해 0.01초마다 쓰레드실행
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

보시는 거와 같이 복잡해 보일 수 있으나, 자세히 보면,

 

핸들러와 스레드 이외엔 별거 없습니다.

 

여기서 onCreate 부분에 버튼과 텍스트 뷰를 참조하고,

 

Calculate_Date 객체를 인스턴스화 해줍니다.

 

그리고,

 

버튼을 리스너 해주고, 그 안에,

 

현재시간을 구하는 메서드와, 시간을 직접 입력하여,

 

그 시간 차를 구하는 메서드를 호출하여 파라미터에 넣어줍니다

 

(이 역시 Calculate_Date 안에 다 있습니다.)

 

그러고 나서 try문으로 예외 처리를 해준 다음,

 

스레드를 실행합니다!

 

그러면, 

 

이제 쓰레드 쪽을 보겠습니다.

 

public class timeThread implements Runnable {
        //타이머 쓰레드
        @Override
        public void run() {
            int i = (int) finallyTime; //여기에 몇 초인지 넣어야 그 때부터 타이머가 시작된다.
            int day = (int) finallyDate; //여기에는 날짜를 넣는데, 마찬가지로 초 형식으로 넣는다.
            Log.d("뭐야", String.valueOf(i));
            while (true) {
                while (isRunning) { //일시정지를 누르면 멈춤
                    Message msg = new Message();
                    msg.arg1 = i++;
                    msg.arg2 = day++;
                    handler.sendMessage(msg); //인자 넣기(
                    try {
                        Thread.sleep(10); //혹시나 멈췄을 경우를 대비해 0.01초마다 쓰레드실행
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

보시면, finallyTime을 전역 변수로 해두고, 저 int i 변수에

 

int로 캐스팅하여 넣어두었습니다.

 

이렇게 하면, 시간이 몇 초 경과했는지, 핸들러에 전달할 수 있습니다.

 

(예를 들어, 8000이란 숫자가 들어가면 8초부터 타이머가 시작됩니다.)

 

int day = (int) finallyDate;  이 날짜 부분도 마찬가지입니다.

 

중요한 건 이 두 부분은  "초" 단위로 넣어야 하는 것인데,

 

Calculate_Date 메서드에서 제가 다 포맷해놨으니,

 

궁금하면 살펴보시면 됩니다.

 

그리고

 

while반복문 처리를 해줍니다.

 

arg1과 arg2에다가 i와 day가 1씩 증가하게 하여,

 

(핸들러에 메시지 전달)

 

시간과 날짜를 구분 짓게 하기 위해 저런 식으로 arg를 나누어 두었습니다.

 

붙여서 쓰셔도 됩니다.

 

저렇게 전달되고,

 

혹시나 멈추는 상황을 대비해 0.01초마다 스레드를 실행하게 하는 

 

Thread.sleep을 넣어주었습니다.

 

 Handler handler = new Handler(Looper.myLooper()) { //실시간 날짜를 출력해주는 핸들러
        @Override
        public void handleMessage(Message msg) {

            //(msg.arg1 / 100) 이 1초이다. 1초는 1000밀리세컨드이므로,
            //int min = (msg.arg1 / 100) / 60 같은 경우는 1/60이니까 분이다. (시간도 마찬가지)
            int sec = (msg.arg1 / 100) % 60; //초
            int min = (msg.arg1 / 100) / 60 % 60; //분
            int hour = (msg.arg1 / 100) / 3600 % 24; //시
            int day = (msg.arg2 / 100) / 86400; //하루

            String result = String.format("%02d:%02d:%02d", hour, min, sec);
            Log.d("리절트", result);

            String oneDay = String.format("%d", day);
            Log.d("원데이", oneDay);

            /** result 실시간 시간초이다.*/
            textTime.setText("오늘을 기준으로\n\n" + result + "버틴 시간"); //시간표시
            textDate.setText("오늘 기준으로" + oneDay + "일 지났습니다."); //날짜표시
        }
    };

 

그리고 핸들러 부분을 보시면,

 

메시지를 전달받고 초, 시간, 분, 하루 단위로

 

저런 식으로 쓰여있습니다.

 

msg.arg1이나 msg.arg2 같은 경우는 1초마다

 

1000밀리 세컨드이므로, 1000을 100으로 나누어 줌으로써

 

값은 1이 됩니다.

 

% 는 산술 연산자로 다음에 나오는 숫자(같은 byte) 와 같아야 합니다.

 

그래서 int sec = (msg.arg1 / 100) % 60; 를 보시면,

 

60초까지 가면, 바로 00초로 바뀌는 걸 아실 수 있습니다.

 

나머지 분, 시간, 하루도 같다고 할 수 있습니다.

 

int hour = (msg.arg1 / 100) / 3600 % 24;

 

이 시간 같은 경우도 3600분의 1이니까 한 시간을 의미하고,

 

마찬가지로 산술연산자 % 다음으로 나오는 24시간까지

 

시간으로 표시되고, 그다음부터는 00으로 바뀌는 것을 알 수 있습니다.

 

그리고 String result = String.format("%02d:%02d:%02d", hour, min, sec);

 

를 보시면, 앞에 인자에는 "&02d"라는 것을 3개 넣고, 뒤에 각각 자리에

 

들어갈 시간, 분, 초 인자를 넣어

 

포맷하는 메서드입니다.

 

이로 인해 result 값은 반복문으로 인하여 1초에 한 번씩 증가하여,

 

타이머가 구현되는 것입니다.

 

아래 oneDay도 마찬가지입니다.

 

여기서 잠깐 짚고 넘어가겠습니다.

 

"&02d"가 무엇인가?입니다.

 

% 는 명령을 시작한다는 의미이고,

 

0은 채워질 문자,

 

2는 총자릿수를 의미하고,

 

d는 10진수 즉, 정수를 의미합니다.

 

타이머를 다룰 때 자주 사용되는 

 

문자열 포맷팅을 위한 문법입니다.

 

그리고 xml문과 Caculate_date.java를 올려드리겠습니다.

 

public class Calculate_Date {

    public String WhatTimeIsItAll() { //전체 다
        //현재 시간과 날짜를 나타내는 메서드
        long now = System.currentTimeMillis();

        Date mDate = new Date(now);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        String getAll = simpleDateFormat.format(mDate); //스트링 형태로 현재 날짜 시간을 가져옴.

        return getAll;
    }


    public String WhatTimeIsItDate() { //날짜만
        //현재 날짜를 나타내는 메서드
        long now = System.currentTimeMillis();
        Date mDate = new Date(now);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); //수정가능
        String getDay = simpleDateFormat.format(mDate); //스트링 형태로 현재 날짜를 가져옴.

        return getDay;
    }

    public String WhatTimeIsItTime() { //시간만
        //현재 시간을 나타내는 메서드
        long now = System.currentTimeMillis();
        Date mDate = new Date(now);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss"); //수정가능
        String getTime = simpleDateFormat.format(mDate); //스트링 형태로 현재 시간을 가져옴.

        return getTime;
    }

    public long calDateBetweenAandB(String date1, String date2) throws ParseException //날짜 차이 구하기 "yyyy-mm-dd HH:mm" 이런 형식으로 넣어야함.
    {

            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); //수정가능
            // date1, date2 두 날짜를 parse()를 통해 Date형으로 변환.
            Date FirstDate = format.parse(date1);  //지정한날(금연 시작날)
            Date SecondDate = format.parse(date2); //현재 날짜

            // Date로 변환된 두 날짜를 계산한 뒤 그 리턴값으로 long type 변수를 초기화 하고 있다.
            // 연산결과 -950400000. long type 으로 return 된다.
            long calDate = SecondDate.getTime() - FirstDate.getTime();
            long lastCalDate = calDate/10; //연산 후에는 0이 하나 더 추가되어, 이렇게 10으로 나누어 준다.
            Log.d("칼데이트", String.valueOf(FirstDate));
            Log.d("칼데이트", String.valueOf(SecondDate));
            Log.d("칼데이트", String.valueOf(calDate));
            Log.d("칼데이트", String.valueOf(lastCalDate));

            return lastCalDate;
    }

    public long calTimeBetweenAandB(String time1, String time2) throws ParseException { //시간 차이 구하기 "HH:mm:ss" 이런 형식으로 넣어야함.
        SimpleDateFormat f = new SimpleDateFormat("HH:mm:ss", Locale.KOREA);
        Date d1 = f.parse(time1);
        Date d2 = f.parse(time2);
        long diff = d2.getTime() - d1.getTime();
        long lastDiff = diff/10; //연산 후에는 0이 하나 더 추가되어, 이렇게 10으로 나누어 준다.
        Log.d("디프", String.valueOf(d2));
        Log.d("디프", String.valueOf(d1));
        Log.d("디프", String.valueOf(diff));
        Log.d("디프", String.valueOf(lastDiff));
        return lastDiff;
    }

}

쓰기 좋게 나누어 놓았으니, 필요에 맞게 쓰시면 됩니다.

 

중요한 건 calTimeBetweenAandB와 calDateBetweenAandB에서

 

calDate와 diff를 구하고,

 

다시 10으로 나누어 last를 붙인 long형태에 변수에 담아서

 

그대로 리턴을 하는 것입니다.

 

저도 사실 이유는 모르겠지만,

 

연산 후에는 0이 더 추가되어서 나와 가지고, 저렇게 만들었답니다.

 

이유를 아시는 분은 친절한 설명 부탁드립니다.

 

그리고 나머지 xml입니다.

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="날짜결과"
        android:textSize="30sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/checkBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="224dp"
        android:text="둘다계산"
        app:layout_constraintBottom_toTopOf="@+id/textView_date"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <TextView
        android:id="@+id/textView_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="시간결과"
        android:textSize="25sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_date" />

</androidx.constraintlayout.widget.ConstraintLayout>

이렇게 마무리를 하면

 

 

빼는 시간이 더 뒤에 있어서 -로 나오지만 이거는 순서를 바꾸거나,

 

날짜나 시간 값을 더 크게 하면 됩니다.

 

그냥 단순히 시간 차이를 구하고 싶으신 분들은

 

Math.abs메서드를 이용해

 

절댓값을 구하셔서 사용하시면 됩니다.

 

이상 초보 안드 개발자 자팍이였습니다.

 

감사합니다.

 

코드는 깃헙에 올려두었습니다.

 

github.com/qjsqjsaos/Tistory3

 

qjsqjsaos/Tistory3

현재시간, 현재날짜, 시간 차이 구하기, 날짜 차이 구하기 입력 값을 받는 타이머 구현, 금연 앱 같은 스톱워치앱을 만들기 유용 - qjsqjsaos/Tistory3

github.com

 

728x90
반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading