온라인 웹 에디터 :
http://jsbin.com/?html,console,output
https://repl.it
https://codepen.io
특정 날짜의 보팅 내역 조회 : https://steemcoding.github.io/dicegame.github.io/votingday.html
지난 시간에 Steem.js API를 다룰때 많이 사용하는 자바스크립트 Date()함수에 대해서 살펴 보았습니다. post를 작성하다가 문득 "현재시간을 기준으로 24시간 동안 보팅한 내역 응용"을 가지고 특정 날짜에 대한 보팅 내역을 찾고 싶어 지더군요. 그래서, 한번 자신이 확인하고 싶은 날짜를 선택하면 그 날짜의 보팅 내역만 찾아 보는 실험을 해보았습니다. 사실, 실험의 결과물은 별 의미가 없습니다. 그냥 Date()함수를 이용하여 제가 원하는 결과를 찾았을 뿐이죠. 현재시간을 기준으로 24시간 동안 보팅한 내역을 찾는 코딩을 할 수 있지만 생각하는 방향을 조금만 수정하면 이것을 이용하여 원하는 날짜의 보팅 내역을 조회 할 수 있습니다. 그것을 실험하기 위해 일요일에 잠깐 코딩을 하였습니다. Date() 함수의 좋은 응용 예제가 될 것 같아서 Date()함수 post를 쓰면서 떠오르는 상상력을 정리해 놓고 일요일날 실제 코딩화 해서 만들어 봤네요.
어떻게 만들었는지 그 과정을 살펴보도록 하겠습니다.
특정 날자의 보팅 내역을 어떻게 얻는 방법은 이와 같은 과정으로 우선 설계 했습니다.
[ 설계 내용 ]
steem.api.lookupAccounts(lowerBoundName, limit, function(err, lookupAccounts) {
console.log(err, lookupAccounts);
});
steem.api.getAccountVotes(author, function(err, accountVotes) {
console.log(err, accountVotes);
});
var query = {
"tag": "author",
"limit": 1,
"start_author": "author",
"start_permlink": "permlink" };
steem.api.getDiscussionsByBlog(query, function(err, discussionsByBlog) {
console.log(err, discussionsByBlog);
});
tag은 해당 블로그 계정ID입니다. limit은 가져올 갯수이고, start_author(시작저자위치), start_permlink(시작post주소) 이둘로 블로그의 시작 위치를 결정 합니다.
이렇게 세개의 함수를 이용하면 제가 원하는 특정 날짜의 보팅 내역을 조회가 가능해 집니다.
steem.api.lookupAccounts(myId, 1, function(err, lookupAccounts) {
console.log(err, lookupAccounts);
});
이 함수로 조회 가능한 계정인지 알 수 있습니다. myId은 저자의 계정ID 입니다. 그 ID가 정상적인 ID인지 찾기 위한 함수로 사용합니다. 참고로, 이 함수는 입력된 ID에 일치한 ID나 가장 근접한 ID가 lookupAccounts 변수에 저장되게 됩니다. 필요한 것은 1개니깐 limit은 1로 해야 겠죠.
IF 조건문 하나면 쉽게 판단이 됩니다.
if(myId!=lookupAccounts) alert('error ID');
else myVoting(myId);
이렇게 myId은 html 입력 태그에서 입력된 ID이고 lookupAccounts은 조회된 ID로 두 ID가 일치하지 않으면 없는 존재하지 않는 계정ID으로 경고창 alert()함수로 알리게 됩니다. 그리고, 다음 동작으로 넘어가지 못하게 멈추게 됩니다. 만약 일치하게 되면 사용자 정의함수 myVoting(myId) 으로 다음 동작으로 넘어가게 합니다. 일치할 때만 조회가 진행되게 IF문으로 락을 걸어 놓은 것이죠.
ID가 정상적으로 입력되었으니깐 이제 보팅 내역을 조사 해야 겠죠.
function go(){
var myDate = $("#myDate").val();
steem.api.lookupAccounts(myId, 1, function(err, lookupAccounts) {
if(myId!=lookupAccounts) alert('error ID');
else myVoting(myId);
});
}
Steem 블록체인에 기록된 시간값은 ISO 형식으로 기록 됩니다. 참고로 한국시간으로 따지면 -9시간 차가 발생하네요. 그래서 시간에 대한 계산이 필요합니다. 만약 5월 12일을 선택한다면 5월 12일 0시~24시까지 보팅한 내역을 출력해야 하는데 선택할 날짜의 시작 0시를 기준으로 Steem 블록체인 시간은 -9시간으로 검색을 해야하기 때문에 시간을 변경해야 합니다.
이렇게 시간을 만들면
var myDate = '2018-05-13'
var dt = new Date(myDate);
console.log(dt.toISOString());
결과 => "2018-05-13T00:00:00.000Z"
이렇게 나오게 되는데 Steem 블록체인에 기록된 시간에 맞게 검색할려면 -9시간을 해야 합니다 지난 시간에 배운 시간함수로 이용하여
dt.setHours(dt.getHours() - 9);
결과 => "2018-05-12T15:00:00.000Z"
이렇게 구할 수 있습니다. 선택할 날짜에 24시간동안의 보팅 내역이니깐 -9시간을 한 시간값에서 1일 동안의 보팅 내역을 출력할려면 24시간 후의 시간대 값을 구해야 합니다. 시작 시간은 구했으니깐 종료 시간을 구해야 합니다.
var myDate = '2018-05-13'
var dt = new Date(myDate);
var startDate = new Date(dt.setHours(dt.getHours() - 9)).toISOString().split('.')[0];
var endDate = new Date(dt.setDate(dt.getDate()+1)).toISOString().split('.')[0];
console.log(startDate);
console.log(endDate);
결과 =>
"2018-05-12T15:00:00"
"2018-05-13T15:00:00"
이렇게 특정 날짜의 24시간의 시작시간과 종료시간을 구할 수 있게 되었죠.
여기서, 특정 날짜의 보팅 한 한국시간을 알아야 합니다. Steem 블록체인에 기록된 시간은 한국시간으로 보면 -9시간 차가 있기 때문에 우리가 검색한 Steem 블록체인의 시간으로 18시간의 차이가 발생하게 됩니다. 보팅한 시간을 한국시간으로 바꿀려면 18시간을 더해야 합니다. 즉, ISO 시간을 한국시간형으로 표기하는 것이기 때문에 감안하시고 보세요.
var myDate = '2018-05-13'
var dt = new Date(myDate);
console.log(dt.toISOString());
$("#output").html(dt)
[결과]
"2018-05-13T00:00:00.000Z"
Sun May 13 2018 09:00:00 GMT+0900 (대한민국 표준시)
이렇게 코딩을 하면 한국시간에서 -9시간인 시간으로 ISO을 한국표준 시간으로 보여준다면 ISO 한국형 형식의 시간은 +18시간을 해야 한국형 시간이 나오게 됩니다.
dt.setHours(dt.getHours() +9);
"2018-05-13T09:00:00.000Z"
이렇게 출력되게 할려면 +9시간이 되어야 겠죠. 그런데, 선택한 날짜의 0시가 실제 표준 ISO 시간과 -9시간차이기 때문에 -9시간 차에서 검색된 시간값은 한국형으로 바꿀려면 총 18시간의 차가 발생합니다.
var dt = new Date(accountVotes[d].time);
var koreaTime = new Date(dt.setHours(dt.getHours() +18)).toISOString().split('.')[0];
accountVotes에 기록된 보팅 정보의 시간은 한국시간으로 -9시간이고 추출한 블록날짜로 기준으로 따지면 -9시간이 됩니다.
dt.setHours(dt.getHours() +18)
이렇게 해서 추출 날짜의 보팅한 한국형시간 형식으로 구할 수 있게 됩니다. 아마 이부분이 좀 햇갈리 실 꺼에요. -9시간 차이면 +9시간만 하면 되지 왜 +9시간을 더 하냐고 말하겠지요. 그 이유는 우리가 선택한 날짜를 기준으로 조회를 하기 때문에 선택한 날짜가 -9시간의 차이가 발생합니다. 원래 블록체인의 시간은 -9시간 정도 차이가 나는데 선택한 시간에도 -9시간이 발생하기 때문에 기록된 시간의 원래 한국 시간으로 ISO로 총 18시간의 차이나는 시간으로 표기 됩니다. ISO로 한국형 시간으로 출력되게 할려면 총 18시간이 더해진 시간으로 나와야 한국형 ISO형식이 나오게 됩니다. 참 번거로운 표현이지요. ISO 추출한 값을 비교할려고 하니깐 이런 문제가 생겼네요. 이 수치는 자신의 나라에 맞게 현재시간과 Steem 블록체인의 시간 차에 맞게 숫자를 변경하면 자신의 나라의 시간대로 수정이 가능해 지겠죠.
위 방식은 추천하지 않습니다. 왜냐면 그냥 시간출력을 ISO 느낌의 시간으로 표현한 것이기 때문입니다. 이 값을 가지고 Steem 블록체인과 비교를 하게 되면 오히려 혼동을 야기 할 수 있기 때문이죠. 시간을 ISO 표현을 한국형기준으로 나타낸 것이기 때문에 이 기준으로 Steem 블록체인 시간 값과 동일 시간대로 보시면 큰일 납니다. 무려 18시간의 차이가 발생하기 때문에 혼동을 야기 할 수 있습니다. 그냥 시간은 블록체인에 기록된 ISO 시간으로 출력 되게 하셔야 혼동이 없을꺼에요.
var myDate = '2018-05-13T09:00:00.000Z'
var dt = new Date(myDate);
console.log(dt.toISOString());
$("#output").html(dt)
[결과]
"2018-05-13T09:00:00.000Z"
Sun May 13 2018 18:00:00 GMT+0900 (대한민국 표준시)
이렇게 엉뚱한 결과를 발생할 수 있기 때문이죠. 그래서, 정확히 그 의미와 사용목적에 따라서 써야 합니다. 머리가 복잡하시면 그냥 위의 ISO 한국형 시간 계산 로직은 지워 주시고 아래 코딩 부분에서 해당 로직은 삭제하시면 됩니다.
아래 부분에서 코딩 설명에서 해당 명령 라인이 있는데 그 코딩에서,
var dt = new Date(accountVotes[d].time);
이부분을
var koreaTime = new Date(accountVotes[d].time);
이렇게 하고 나머지 명령 라인을 삭제하시고 출력하시면 됩니다.
시간 함수를 이상으로 마무리 하고 이걸 가지고 특정 날자의 보팅 내역을 찾아 볼까요.
myVoting(myId) 함수를 실행하면 외부의 특정 날짜가 입력을 받아서 그 시간으로 startDate(시작시간), endDate(종료시간)을 아래와 같이 구할 수 있겠죠.
function myVoting(myId) {
var myDate = $("#myDate").val();
var dt = new Date(myDate);
var startDate = new Date(dt.setHours(dt.getHours() - 9)).toISOString().split('.')[0];
var endDate = new Date(dt.setDate(dt.getDate()+1)).toISOString().split('.')[0];
render(myId, startDate, endDate);
}
이렇게 해서 여기에는 계정ID(myId), startDate(시작시간), endDate(종료시간)을 구했습니다. 이 정보를 토대로 특정 날짜의 보팅 내역을 추출 할 수 있습니다. render()함수에 이 세개의 인자를 넘겨 보팅 내역을 검색을 진행 합니다.
steem.api.getAccountVotes(author, function(err, accountVotes) {
console.log(err, accountVotes);
});
위 함수를 이용해서 해당 계정의 보팅한 내역을 가져 올 수 있습니다. author(myId)의 보팅 내역이 accountVotes변수에 들어 있습니다. 여기에는 전체 보팅 내역이 들어 있는데 여기서 우리는 특정 날짜의 정보를 가져 와야 합니다.
IF문으로 해서 해당 조건이 만족하는 데이터만 추출하면 됩니다.
for(d in accountVotes){
if(accountVotes[d].time>=startTime && accountVotes[d].time<=endTime){
특정 날짜의 시작 시간보다 크거나 같고 종료시간보다 작거나 같을 때 참;
}
}
accountVotes의 데이터를 하나씩 순차적으로 꺼내는데 if문으로
startTime<=accountVotes[d].time<=endTime
이 조건이 만족하는 보팅 내역만 참이 될 때 참이 된 보팅 내역만 출력하면 됩니다. 이렇게 시간 함수로 얻은 시간값을 가지고 원하는 특정 날짜의 보팅 내역을 추출 할 수 있겠죠.
function render(author, startTime, endTime){
steem.api.getAccountVotes(author, function(err, accountVotes) {
// console.log(err, accountVotes);
for(d in accountVotes){
if(accountVotes[d].time>=startTime && accountVotes[d].time<=endTime){
var data = accountVotes[d].authorperm.split('/');
var author = data[0];
var permlink = data[1];
var dt = new Date(accountVotes[d].time);
var koreaTime = new Date(dt.setHours(dt.getHours() +18)).toISOString().split('.')[0];
//보팅한 포스트
votingpost(author, permlink,koreaTime);
cnt+=1;
}
}
});
html 출력하는 코딩을 뺀 순수 동작 코딩입니다. 보시면 if문 안에 몇개의 코딩 명령이 있습니다. 여기서, author은 계정ID이고, permlink은 보팅한 Post 주소입니다. 그리고, accountVotes[d].time은 보팅한 시간이 됩니다. 여기서 보팅한 시간은 실제 한국시간으로 따지면 18시간의 차이가 발생 한다고 했죠.
그러면 한국시간으로 보기 위해서는
var dt = new Date(accountVotes[d].time);
var koreaTime = new Date(dt.setHours(dt.getHours() +18)).toISOString().split('.')[0];
이렇게 해서 koreaTime에는 한국 시간값을 저장 되어 있습니다. 이상태로해서 저자, post주소, 보팅시간을 바로 출력하면 마무리가 됩니다.
여기서, post 주소를 출력하자니 다소 보기가 그래서 보팅한 post의 제목을 출력시켜보고 싶어지더군요. 그래서 post의 title을 가져오기 위해서 추가 코딩을 진행 했습니다.
그냥, 추출된 정보만을 html로 출력하면 되지만 추가로 좀 더 보기 좋게 표현을 해보았습니다.
votingpost(author, permlink, koreaTime);
제목을 구하기 위해서 사용자 정의 함수를 하나 더 만들었네요. author(저자), permlink(post주소), koreaTime(보팅시간)이렇게 추출한 세가지 정보를 사용자 정의 함수 votingpost()에 넘겨 줍니다.
var query = {
"tag": "author",
"limit": 1,
"start_author": "author",
"start_permlink": "permlink" };
steem.api.getDiscussionsByBlog(query, function(err, discussionsByBlog) {
console.log(err, discussionsByBlog);
});
Post 정보를 얻는 함수는 여러개가 있지만 getDiscussionsByBlog()함수로 그냥 제목을 가져왔네요. votingpost() 함수에는 author(저자), permlink(보팅Post), koreaTime(보팅시간) 이렇게 세개의 인자가 넘어 옵니다. 여기서 필요한 것은 2개만 있으면 됩니다. 해당 post의 블로그 tag은 author이고 시작 저자(start_author)는 author입니다. 그리고 시작 post(start_permlink)은 permlink가 됩니다. 그리고 가져올 post는 보팅한 post니깐 한개로 limit은 1이 됩니다. 이렇게 하면 해당 post의 정보만 가져오게 됩니다.
var query = {
"limit": 1
};
query.tag = author;
query.start_author = author;
query.start_permlink = permlink;
이렇게 해서 query 문을 만들었습니다. 이제 검색을 해야겠죠.
steem.api.getDiscussionsByBlog(query, function(err, discussionsByBlog) {
console.log(err, discussionsByBlog);
});
이렇게 하면 discussionsByBlog에는 한개의 보팅한 post 정보가 저장 되어 있습니다. 제목은 discussionsByBlog[0].root_title에 들어 있습니다. 이렇게 해서 원하는 3가지 정보를 다 구했습니다.
특정 날짜에 보팅한 스티미언의 저자, post 제목, 보팅시간의 데이터를 다 찾았습니다.
이것을 html로 출력하기 위해서 테이블을 이용했습니다.
var output = '' +author+'' +discussionsByBlog[0].root_title+'' +time+'';
$('#output').append(output);
output로 테이블 태그와 함께 해당 출력 위치에 저자, post 제목, 보팅 시간을 넣고 output 변수의 그 결과를 저장 합니다. 그리고 jQuery 명령어 id가 "output"인 태그인 테이블에 해당 데이터를 append로 추가하게 html로 출력 됩니다.
Bootstrap 를 이용해서 디자인 부분을 대신 했네요. 직접 css 코딩을 해야 하는데 의미전달이 목적이니깐 간단히 구현 했네요.
크롬 창에서 열었습니다. 브라우저 마다 달력이 다릅니다. 가장 이쁜 달력은 파이이폭스창에서 열릴 때 이쁜 달력이 나오네요
아래 소스는 조잡한 코딩으로 웹 코딩하는 분들이 보면 유치한 수준의 코딩입니다. Date()함수의 응용을 전달하기 위한 코딩임을 감안하시고 보시기 바랍니다. 좀 많은 부분들을 생략한 코딩입니다.
[vodingday.html]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>
</head>
<body>
<form class="form-inline">
<div class="form-group mb-2">
<span class="input-group-text" id="basic-addon1">@</span>
<input type="text" class="form-control" id="myId" placeholder="Username" aria-label="Username" aria-describedby="basic-addon1">
</div>
<div class="form-group mx-sm-3 mb-2">
<input class="input-group-text" type="Date" id="myDate" />
</div>
<div class="form-group mb-2">
<button type="button" class="btn btn-primary" onclick="go()">조회</button>
</div>
</form>
<div id ="count"></div>
<table class="table table-striped" id="output"></table>
<script src="votingday.js"></script>
</body>
</html>
[vodingday.js]
document.getElementById('myDate').valueAsDate = new Date();
function go(){
var myId= $("#myId").val();
steem.api.lookupAccounts(myId, 1, function(err, lookupAccounts) {
if(myId!=lookupAccounts) alert('error ID');
else myVoting(myId);
});
}
function myVoting(myId) {
var myDate = $("#myDate").val();
var dt = new Date(myDate);
var startDate = new Date(dt.setHours(dt.getHours() - 9)).toISOString().split('.')[0];
var endDate = new Date(dt.setDate(dt.getDate()+1)).toISOString().split('.')[0];
render(myId, startDate, endDate);
}
function render(author, startTime, endTime){
steem.api.getAccountVotes(author, function(err, accountVotes) {
// console.log(err, accountVotes);
var cnt = 0;
var output='ID Post KOREA TIME ';
$('#output').html(output);
for(d in accountVotes){
if(accountVotes[d].time>=startTime && accountVotes[d].time<=endTime){
var data = accountVotes[d].authorperm.split('/');
var author = data[0];
var permlink = data[1];
var dt = new Date(accountVotes[d].time);
var koreaTime = new Date(dt.setHours(dt.getHours() +18)).toISOString().split('.')[0];
//보팅한 포스트
votingpost(author, permlink,koreaTime);
cnt+=1;
}
}
var count = 'Count '+cnt+'unread messages'
$('#count').html(count);
$('#output').append('');
});
function votingpost(author, permlink,time){
var query = {
"limit": 1
};
query.tag = author;
query.start_author = author;
query.start_permlink = permlink;
steem.api.getDiscussionsByBlog(query, function(err, discussionsByBlog) {
var output = '' +author+'' +discussionsByBlog[0].root_title+'' +time+'';
$('#output').append(output);
});
}
}
두개 파일을 메모장에다 votingday.html, vodingday.js로 확장자를 정확히 지정하여 저장하여 html 문서로 여시면 실행이 가능합니다.
$('#output').html(output);
output에 들어 있는 값을 id가 "output"인 태그에 html 형식으로 출력하라는 의미 입니다.
$('#output').append(output);
id가 "output"인 태그에 append가 추가하는 명령으로 기존에 있는 값을 그대로 유지한 상태에서 output에 들어있는 값을 추가하게 됩니다.
$("#myDate").val();
id가 "myDate인 태그에 값을 가져옵니다.
document.getElementById('myDate').valueAsDate = new Date();
이건 자바스크립트로 그냥 표현 했네요. 이것은 input 날짜 태그에 오늘 날짜로 값을 설정하는 표현입니다.
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.steemjs.com/lib/latest/steem.min.js"></script>
bootstrap, jquery, steem.js를 사용하기 위해서 링크를 선언 했네요.
위 사이트 가셔서 html 예제들을 보고 원하는 형태를 적용하면 보기 좋게 디자인이 가능해 집니다.
사실 html에 관련된 부분은 가져다가 조합해서 사용했기 때문에 따로 디테일적인 표현은 없습니다.
JavaScript, jQuery를 제대로 공부한 적이 없고 둘을 합쳐서 공부한 시간은 얼마 되지 않습니다. 잠깐 본 것이 전부라 약간 두 가지를 혼합된 코딩으로 조잡 합니다. 중요 한것은 Date() 시간함수를 사용하면 이런 것들을 표현 할 수 있다는 것을 보여주기 위한 예제로 간단히 구현한 내용임을 감안하시고 보시기 바랍니다.(전, 웹언어랑은 안친함)
이전 Date() 함수에 대한 post를 작성하면서 문득 떠오른 내용을 생각했다가 일요일에 생각한 것들을 코딩하고 그 내용을 이렇게 post로 풀어 봤네요. Date()라는 함수가 Steem.js에 적용하면 이렇게 재밌는 표현을 할 수 있게 됩니다. Date() 함수가 사실 별로 어렵지 않는 함수라 사용하기 편하고 이 함수를 어떻게 사용 하느냐에 따라서 표현은 다양해 집니다.
현재시간 기준 24시간 보팅내역을 출력하는 코딩에서 업그레이드한 특정 날짜의 보팅 내역을 출력한 예제이지만 여기서 좀 더 업그레이드 한다면 특정 기간의 보팅 내역을 조회도 가능합니다. 위 3번에 내용에서 시간을 html 날짜 입력태그로 선택한 날짜를 한개를 기준으로 0~24시간을 만들어 냈지만 html 날짜 입력태그를 2개 만들어서 사용하면 하나는 시작시간이고 하나는 종료시간으로 수정하면 쉽게 특정 기간의 보팅 내역 조회가 가능합니다. 이 부분은 여러분들이 직접 구현해 보시기 바랍니다.
그리고, 여러분들도 한번 다른 Steem.js API 함수들을 Date()함수로 적용하면 어떤 것을 만들어 낼 수 있을지 상상의 나래를 펼쳐 보세요.
휴! Post 겨우 완성을 했네요. 이 내용을 작성 한 뒤에 클릭 실수로 post 작성한 내용이 전부 날라 갔네요. 처음에 작성한 내용이 괜찮았는데 Markdown 온라인편집기에서 페이지 전환이 되는 바람에 이전 기록한 post 내용이 사라지고 다시 처음부터 기억을 더듬어서 또 다시 작성하려고 하니 귀찮아서 대충 쓴 것 같네요. 처음 작성한 post가 괜찮았는데 아쉬울 따름입니다.
어쩔 수 없이 다시 post 작성했는데 코딩은 얼마 안걸렸는데 post가 꽤 시간을 잡아 먹었네요.